diff -r 000000000000 -r 72b543305e3a mmsengine/clientmtm/src/mmsclient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmsengine/clientmtm/src/mmsclient.cpp Thu Dec 17 08:44:11 2009 +0200 @@ -0,0 +1,2858 @@ +/* +* 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: mmsclient implementation +* +*/ + + + +// INCLUDE FILES +#include +#include +#include +#include +#include +#include +#include +#include +#include // CMsvFindText +#include +#include +#include +#include +#include + +// mms headers +#include "mmsheaders.h" +#include "mmssettings.h" +#include "mmsclient.h" +#include "mmsmessageoperation.h" +#include "mmsgenutils.h" +#include "mmscmds.h" +#include "mmsattachmenthandler.h" +#include "mmssendingchain.h" +#include "mmsattachmentwaiter.h" +#include "mmssendmessageoperation.h" + +// EXTERNAL DATA STRUCTURES + +// EXTERNAL FUNCTION PROTOTYPES + +// CONSTANTS +#ifdef _DEBUG +#undef _NO_MMSC_LOGGING_ +#endif + +_LIT( K1970, "19700000:000000.000000" ); // 1-Jan 1970 0:00:00 + +// MACROS + +// LOCAL CONSTANTS AND MACROS +const TInt KMmsAttributeArrayGranularity = 8; + +// MODULE DATA STRUCTURES + +// LOCAL FUNCTION PROTOTYPES + +// ==================== LOCAL FUNCTIONS ==================== + + +// ================= MEMBER FUNCTIONS ======================= + +// Factory function. +EXPORT_C CMmsClientMtm* CMmsClientMtm::NewL( + CRegisteredMtmDll& aRegisteredMtmDll, + CMsvSession& aSession ) + { + CMmsClientMtm* self=new( ELeave ) CMmsClientMtm( + aRegisteredMtmDll, aSession ); + + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + + return self; + } + + +// Constructor +// Notice that CMmsNotificationClientMtm constructor calls this. +CMmsClientMtm::CMmsClientMtm( + CRegisteredMtmDll& aRegisteredMtmDll, + CMsvSession& aSession ) + : CBaseMtm( aRegisteredMtmDll, aSession ), + iMmsSettings ( NULL ), + iMmsHeaders ( NULL ), + iServiceId ( KMsvNullIndexEntryId ), + iFetchAll( EFalse ), + iFetchOverride( ETrue ), + iOwnSession( aSession ), + iAttaWaiter( NULL ) + { + } + + +// Destructor +CMmsClientMtm::~CMmsClientMtm() + { + delete iAttaWaiter; + // We created the settings, it is ours to delete + delete iMmsSettings; + delete iMmsHeaders; + if ( iAttributes != 0 ) + { + iAttributes->Reset(); + } + delete iAttributes; + } + +// --------------------------------------------------------- +// CMmsClientMtm::CreateNewEntryL +// --------------------------------------------------------- +// +CMsvOperation* CMmsClientMtm::CreateNewEntryL( + TMsvId aDestination, + TRequestStatus& aCompletionStatus) + { + + return CMmsMessageOperation::CreateNewL( + aCompletionStatus, + Session(), + aDestination, + iServiceId ); + } + +// DEPRECATED - TO BE REMOVED IN THE FUTURE +// --------------------------------------------------------- +// CMmsClientMtm::CreateServiceL +// --------------------------------------------------------- +// +void CMmsClientMtm::CreateServiceL() + { + TMsvId service = KMsvNullIndexEntryId; + // load settings in order to be sure the old ones are deleted + iMmsSettings->LoadSettingsL(); + // creates new service entry + new notification and mmbox folder entries + iMmsSettings->CreateNewServiceL( Session() ); + // save the new entry ids into cenrep immediatedly + iMmsSettings->SaveSettingsL(); + // Get the base values to detect changes + // This function should not be idly called, so this should be safe. + iHomeMode = iMmsSettings->ReceivingModeHome(); + iRoamingMode = iMmsSettings->ReceivingModeForeign(); + iAccessPointCount = iMmsSettings->AccessPointCount(); + // service id must be returned + service = iMmsSettings->Service(); + + if ( service == KMsvNullIndexEntryId ) + { + // No new entry created + User::Leave( KErrNotSupported ); + } + SwitchCurrentEntryL( service ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::MmsSettings() +// --------------------------------------------------------- +// +const CMmsSettings& CMmsClientMtm::MmsSettings() + { + return *iMmsSettings; + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetSettingsL +// --------------------------------------------------------- +// +void CMmsClientMtm::SetSettingsL( const CMmsSettings& aSettings ) + { + // copy caller's settings to our member + iMmsSettings->CopyL( aSettings ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::StoreSettingsL() +// --------------------------------------------------------- +// +void CMmsClientMtm::StoreSettingsL() + { + // Check that sufficient disk space available + + if ( iAccessPointCount < iMmsSettings->AccessPointCount() ) + { + // Disk space checked only if the file size increases. + // And the file size increases only when access points are added. + if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( + &Session().FileSession(), + KMmsAccessPointDiskSpaceNeed, + EDriveC ) ) + { + // we use standard error code here + User::Leave( KErrDiskFull ); + } + } + iMmsSettings->SaveSettingsL(); + + // if one of the receiving modes have changed to automatic, + // start fetching deferred messages + TInt homeMode = iMmsSettings->ReceivingModeHome(); + TInt roamMode = iMmsSettings->ReceivingModeForeign(); + + if ( ( homeMode != iHomeMode && homeMode == EMmsReceivingAutomatic ) || + ( roamMode != iRoamingMode && roamMode == EMmsReceivingAutomatic )) + { + // fetch all, but only if fetching mode allows it. + iFetchAll = ETrue; + iFetchOverride = EFalse; + } + else + { + iFetchAll = EFalse; + iFetchOverride = ETrue; + } + + // We don't leave the settings store function just because the automatic + // fetch operation leaves. Some entry may be locked and cannot be fetched + // or some other problem may prevent the fetch. + // Settings are stored anyway. + TInt error = KErrNone; + TRAP( error, + if ( iFetchAll ) + { + // Implicit fetch of messages, wrap asynch method to make it synch. + CMsvOperation* myOperation; + myOperation = NULL; + CMsvOperationActiveSchedulerWait* wait = + CMsvOperationActiveSchedulerWait::NewLC(); + // FetchAllL only schedules notifications in mms folder + myOperation = FetchAllL( wait->iStatus, iFetchOverride ); + // temporary. + CleanupStack::PushL( myOperation ); + wait->Start(); + CleanupStack::PopAndDestroy( myOperation ); + CleanupStack::PopAndDestroy( wait ); + // Then the notifications in inbox + wait = CMsvOperationActiveSchedulerWait::NewLC(); + wait->iStatus = KRequestPending; + // FetchAllFromInboxL only schedules notifications in inbox + myOperation = FetchAllFromInboxL( wait->iStatus, iFetchOverride ); + CleanupStack::PushL( myOperation ); + wait->Start(); + + CleanupStack::PopAndDestroy( myOperation ); + CleanupStack::PopAndDestroy( wait ); + iFetchAll = EFalse; // don't do this next time unless needed... + } + ); + + // Reset the remembered values + iHomeMode = iMmsSettings->ReceivingModeHome(); + iRoamingMode = iMmsSettings->ReceivingModeForeign(); + iAccessPointCount = iMmsSettings->AccessPointCount(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::RestoreSettingsL() +// --------------------------------------------------------- +// +void CMmsClientMtm::RestoreSettingsL() + { + // The settings may have been changed without us knowing it. + // We do not reset saved mode values here, because we try to + // detect if receiving mode has change since we last checked + // in StoreSettingsL() function. + iMmsSettings->LoadSettingsL(); + } + + +// DEPRECATED - TO BE REMOVED IN THE FUTURE +// --------------------------------------------------------- +// CMmsClientMtm::RestoreFactorySettingsL +// --------------------------------------------------------- +// +void CMmsClientMtm::RestoreFactorySettingsL( TMmsFactorySettingsLevel aLevel ) + { + iMmsSettings->LoadSettingsL(); + iMmsSettings->RestoreFactorySettingsL( Session(), aLevel ); + // StoreSettingsL triggers the fetching of messages if the receiving mode + // has changed in a way that requires it. + StoreSettingsL(); + } + + +//---------------------------------------------------------- +// MMS HEADER HANDLING METHODS +//---------------------------------------------------------- + +// --------------------------------------------------------- +// CMmsClientMtm::SetSenderL +// --------------------------------------------------------- +// +void CMmsClientMtm::SetSenderL( const TDesC& aAlias ) + { + iMmsHeaders->SetSenderL( aAlias ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::Sender +// --------------------------------------------------------- +// +const TPtrC CMmsClientMtm::Sender( ) const + { + return iMmsHeaders->Sender(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::MessageClass +// --------------------------------------------------------- +// +void CMmsClientMtm::SetMessageClass( TMmsMessageClass aMessageClass ) + { + iMmsHeaders->SetMessageClass( aMessageClass ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::MessageClass +// --------------------------------------------------------- +// +TInt CMmsClientMtm::MessageClass() const + { + return iMmsHeaders->MessageClass(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetMessagePriority +// --------------------------------------------------------- +// +void CMmsClientMtm::SetMessagePriority( TMmsMessagePriority aPriority ) + { + iMmsHeaders->SetMessagePriority(aPriority); + } + +// --------------------------------------------------------- +// CMmsClientMtm::MessagePriority +// --------------------------------------------------------- +// +TInt CMmsClientMtm::MessagePriority() const + { + return iMmsHeaders->MessagePriority(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetSenderVisibility +// --------------------------------------------------------- +// +void CMmsClientMtm::SetSenderVisibility( TMmsMessageSenderVisibility aVisibility ) + { + iMmsHeaders->SetSenderVisibility(aVisibility); + } + +// --------------------------------------------------------- +// CMmsClientMtm::SenderVisibility +// --------------------------------------------------------- +// +TInt CMmsClientMtm::SenderVisibility() const + { + return iMmsHeaders->SenderVisibility(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetDeliveryReport +// --------------------------------------------------------- +// +void CMmsClientMtm::SetDeliveryReport( TMmsMessageDeliveryReport aVisibility ) + { + iMmsHeaders->SetDeliveryReport(aVisibility); + } + +// --------------------------------------------------------- +// CMmsClientMtm::DeliveryReport +// --------------------------------------------------------- +// +TInt CMmsClientMtm::DeliveryReport() const + { + return iMmsHeaders->DeliveryReport(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetReadReply +// --------------------------------------------------------- +// +void CMmsClientMtm::SetReadReply( TMmsMessageReadReply aRequest ) + { + iMmsHeaders->SetReadReply(aRequest); + } + +// --------------------------------------------------------- +// CMmsClientMtm::ReadReply +// --------------------------------------------------------- +// +TInt CMmsClientMtm::ReadReply() const + { + return iMmsHeaders->ReadReply(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetMessageRootL +// --------------------------------------------------------- +// + +void CMmsClientMtm::SetMessageRootL( const TMsvAttachmentId aId ) + { + // We cannot check if the attachent id is legal because Symbian + // message server panics if the store is already open. + // We must just trust the caller. + iMmsHeaders->SetMessageRoot( aId ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::MessageRootAttachment +// --------------------------------------------------------- +// +TMsvAttachmentId CMmsClientMtm::MessageRootAttachment() const + { + // This function only returns what has been set earlier by the caller. + // As the caller can manipulate the attachments without calling + // MMS Client MTM, we cannot keep track of the presence of the root + // attachment. It is up to the user to handle the case where the root + // has been deleted. + return iMmsHeaders->MessageRoot(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::SendingDate +// --------------------------------------------------------- +// +TTime CMmsClientMtm::SendingDate() const + { + + TInt64 inSeconds = iMmsHeaders->Date(); + + TTime y1970( K1970 ); + + // 1970 presented as microseconds after January 1st, 0 AD Gregorian. + TInt64 ms1970 = y1970.Int64(); + + // If not defined in message headers return 0 + if ( inSeconds == 0 ) + { + return TTime( 0 ); + } + + return TTime( ms1970 + ( inSeconds * KMmsMillion ) ); + + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetMaximumImage +// --------------------------------------------------------- +// +void CMmsClientMtm::SetMaximumImage( TInt aHigh, TInt aWidth ) + { + iMmsHeaders->SetMaximumImage( aHigh, aWidth ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::GetMaximumImage +// --------------------------------------------------------- +// +void CMmsClientMtm::GetMaximumImage( TInt& aHeight, TInt& aWidth ) const + { + iMmsHeaders->GetMaximumImage( aHeight, aWidth ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetExpiryInterval +// --------------------------------------------------------- +// +void CMmsClientMtm::SetExpiryInterval( + TTimeIntervalSeconds aInterval ) + { + iMmsHeaders->SetExpiryInterval(aInterval.Int()); + } + +// --------------------------------------------------------- +// CMmsClientMtm::ExpiryInterval +// --------------------------------------------------------- +// +TTimeIntervalSeconds CMmsClientMtm::ExpiryInterval() const + { + TTimeIntervalSeconds seconds(iMmsHeaders->ExpiryInterval()); + + return seconds; + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetExpiryDate +// --------------------------------------------------------- +// +void CMmsClientMtm::SetExpiryDate( TTime aDate ) + { + + TTime y1970( K1970 ); + TTimeIntervalMicroSeconds interval; + // we can't use "seconds from" as it only returns a + // 32 bit signed integer. If fails in 2038. + // "microseconds from" returns a 64 bit signed integer + interval = aDate.MicroSecondsFrom( y1970 ); + if ( interval.Int64() > 0 ) + { + // expiry date in iMmsHeaders() in seconds from 1.1.1970. + iMmsHeaders->SetExpiryDate( ( interval.Int64() ) / KMmsMillion ); + } + } + +// --------------------------------------------------------- +// CMmsClientMtm::ExpiryDate +// --------------------------------------------------------- +// +TTime CMmsClientMtm::ExpiryDate() const + { + + TTime y1970( K1970 ); + + // 1970 presented as microseconds after January 1st, 0 AD Gregorian. + TInt64 ms1970 = y1970.Int64(); + + // Expiry in Seconds after 1.1. 1970 + TInt64 sAfter1970 = iMmsHeaders->ExpiryDate(); + + // If not defined in message headers return 0 + if ( sAfter1970 == 0 ) + { + return TTime(0); + } + + // Expiry in microseconds after 1.1. 1970 + TInt64 msAfter1970; + msAfter1970 = sAfter1970; + msAfter1970 *= KMmsMillion; + + return TTime( ms1970 + msAfter1970 ); + + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetDeliveryTimeInterval +// --------------------------------------------------------- +// +void CMmsClientMtm::SetDeliveryTimeInterval( + TTimeIntervalSeconds aInterval ) + { + iMmsHeaders->SetDeliveryTimeInterval( aInterval.Int() ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::DeliveryTimeInterval +// --------------------------------------------------------- +// +TTimeIntervalSeconds CMmsClientMtm::DeliveryTimeInterval() const + { + TTimeIntervalSeconds seconds( iMmsHeaders->DeliveryTimeInterval() ); + return seconds; + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetDeliveryDate +// --------------------------------------------------------- +// +void CMmsClientMtm::SetDeliveryDate( TTime aDate ) + { + + TTime y1970( K1970 ); + TTimeIntervalMicroSeconds interval; + // we can't use "seconds from" as it only returns a + // 32 bit signed integer. If fails in 2038. + // "microseconds from" returns a 64 bit signed integer + interval = aDate.MicroSecondsFrom( y1970 ); + if (interval.Int64() > 0 ) + { + // Delivery date in iMmsHeaders() in seconds from 1.1.1970. + iMmsHeaders->SetDeliveryDate( (interval.Int64() ) / KMmsMillion ); + } + } + +// --------------------------------------------------------- +// CMmsClientMtm::DeliveryDate +// --------------------------------------------------------- +// +TTime CMmsClientMtm::DeliveryDate() const + { + + TTime y1970( K1970 ); + + // 1970 presented as microseconds after January 1st, 0 AD Gregorian. + TInt64 ms1970 = y1970.Int64(); + + // Expiry in Seconds after 1.1. 1970 + TInt64 sAfter1970 = iMmsHeaders->DeliveryDate(); + + // If not defined in message headers return 0 + if ( sAfter1970 == 0 ) + { + return TTime(0); + } + + // Expiry in microseconds after 1.1. 1970 + TInt64 msAfter1970; + msAfter1970 = sAfter1970; + msAfter1970 *= KMmsMillion; + + return TTime( ms1970 + msAfter1970 ); + + } + +// --------------------------------------------------------- +// CMmsClientMtm::SendL +// --------------------------------------------------------- +// +CMsvOperation* CMmsClientMtm::SendL( TRequestStatus& aCompletionStatus, + const TTime aSendingTime /* = TTime( 0 ) */ ) + { + + CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection; + CleanupStack::PushL( selection ); // *** + + // Current entry will be the one to send + selection->AppendL( iMsvEntry->Entry().Id() ); + + // aSendingTime is passed on "as is". + // SendL with selection makes the conversion if needed + CMsvOperation* op = SendL( *selection, aCompletionStatus, aSendingTime ); + + CleanupStack::PopAndDestroy( selection ); + + return op; + + } + +// --------------------------------------------------------- +// CMmsClientMtm::SendL +// --------------------------------------------------------- +// +CMsvOperation* CMmsClientMtm::SendL( + CMsvEntrySelection& aSelection, + TRequestStatus& aCompletionStatus, + TTime aSendingTime ) + { + + if ( aSelection.Count() == 0 ) + { + User::Leave( KErrNotFound ); + } + + CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection; + CleanupStack::PushL( selection ); // *** + + // Move the messages to OUTBOX synchronously + // Parent should be the parent of the first entry in the selection + CMsvEntry* cEntry = NULL; + TMsvId currentParent = iMsvEntry->Entry().Parent(); + cEntry = Session().GetEntryL( aSelection.At( 0 ) ); + CleanupStack::PushL( cEntry ); + currentParent = cEntry->Entry().Parent(); + cEntry->SetEntryL( currentParent ); + +#ifndef _NO_MMSC_LOGGING_ + _LIT( KMmsBefore, "MMSC: Entry parent before move 0x%08X"); + TMmsGenUtils::Log( KMmsBefore, currentParent ); +#endif + if ( currentParent != KMsvGlobalOutBoxIndexEntryId ) + { + TMsvLocalOperationProgress progress; + cEntry->MoveL( aSelection, KMsvGlobalOutBoxIndexEntryId, progress ); + } + +#ifndef _NO_MMSC_LOGGING_ + cEntry->SetEntryL( aSelection.At( 0 ) ); + currentParent = cEntry->Entry().Parent(); + _LIT( KMmsAfter, "MMSC: Entry parent after move 0x%08X"); + TMmsGenUtils::Log( KMmsAfter, currentParent ); +#endif + CleanupStack::PopAndDestroy( cEntry ); + + selection->AppendL( aSelection.Back( 0 ), aSelection.Count() ); + + // Call Server MTM + TCommandParameters parameters; // initialized to zero + TTime now; + // All times in message entries are now UTC time + now.UniversalTime(); + TInt error = KErrNone; + if ( aSendingTime > now ) + { + error = aSendingTime.SecondsFrom( now, parameters.iInitialDelay ); + } + if ( error != KErrNone ) + { + User::Leave( error ); + } + + TCommandParametersBuf paramPack( parameters ); + + CMsvOperation* op = InvokeAsyncFunctionL( + EMmsScheduledSend, + *selection, + paramPack, + aCompletionStatus ); + + CleanupStack::PopAndDestroy( selection ); + + return op; + + } + + +// --------------------------------------------------------- +// CMmsClientMtm::FetchAllL +// --------------------------------------------------------- +// +CMsvOperation* CMmsClientMtm::FetchAllL( TRequestStatus& aCompletionStatus, + TBool aForced ) + { + + iFetchOverride = aForced; + + CMsvEntrySelection* selection = ListMmsFolderNotificationsL(); + CleanupStack::PushL( selection ); + + if ( selection->Count() == 0 ) + { + CleanupStack::PopAndDestroy( selection ); + TPckgC < TMsvId > progress = 0; + aCompletionStatus = KRequestPending; + return CMsvCompletedOperation::NewL( Session(), Type(), progress, + KMsvLocalServiceIndexEntryId, aCompletionStatus ); + } + + TCommandParameters parameters; // initialized to zero + TCommandParametersBuf paramPack( parameters ); + + CMsvOperation* op = NULL; + if ( iFetchOverride ) + { + op = InvokeAsyncFunctionL( + EMmsScheduledReceiveForced, + *selection, + paramPack, + aCompletionStatus ); + } + else + { + op = InvokeAsyncFunctionL( + EMmsScheduledReceive, + *selection, + paramPack, + aCompletionStatus ); + // reset override to default value + iFetchOverride = ETrue; + } + + CleanupStack::PopAndDestroy( selection ); + return op; + } + +// --------------------------------------------------------- +// CMmsClientMtm::SendReadReportL +// --------------------------------------------------------- +// +CMsvOperation* CMmsClientMtm::SendReadReportL( TMsvId aReadMessageId, + TRequestStatus& aCompletionStatus, + TMmsReadStatus aReadStatus /*= EMmsReadStatusRead*/ ) + { + // Get the entry for which the report will be sent + + CMmsHeaders* reportHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() ); + CleanupStack::PushL( reportHeaders ); + CMmsHeaders* originalHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() ); + CleanupStack::PushL( originalHeaders ); + + CMsvEntry* cEntry = NULL; + CMsvStore* store = NULL; + // Restore original headers. + // If we are sending the report to current context, use our own entry + if ( aReadMessageId == iMsvEntry->Entry().Id() && + aReadMessageId != KMsvNullIndexEntryId ) + { + store = iMsvEntry->ReadStoreL(); + CleanupStack::PushL( store ); + originalHeaders->RestoreL( *store ); + CleanupStack::PopAndDestroy( store ); + store = NULL; + } + else + { + // If we cannot get the entry, the function leaves + cEntry = Session().GetEntryL( aReadMessageId ); + CleanupStack::PushL( cEntry ); + store = cEntry->ReadStoreL(); + CleanupStack::PushL( store ); + originalHeaders->RestoreL( *store ); + CleanupStack::PopAndDestroy( store ); + store = NULL; + CleanupStack::PopAndDestroy( cEntry ); + cEntry = NULL; + } + + if ( !iMmsSettings->ReadReplyReportSendingAllowed() || + originalHeaders->ReadReply() != EMmsYes || + originalHeaders->Sender().Length() == 0 || + iMmsHeaders->MessageClass() == EMmsClassAuto ) + { + // We are not allowed to send a read reply, or the sender of the + // original message has not requested a read reply - do not send one. + // We are also not allowed to send a read report to automatic messages. + CleanupStack::PopAndDestroy( originalHeaders ); + originalHeaders = NULL; + CleanupStack::PopAndDestroy( reportHeaders ); + reportHeaders = NULL; + + TPckgC < TMsvId > progress = 0; + return CMsvCompletedOperation::NewL( Session(), Type(), progress, + KMsvLocalServiceIndexEntryId, aCompletionStatus, KErrGeneral ); + } + + // Now we have loaded the original headers and decided that a read + // report really must be sent. + // We create a new message entry in the MMS Notification folder to keep + // it invisible. + + reportHeaders->SetMessageIdL( originalHeaders->MessageId() ); + reportHeaders->SetMessageType( KMmsMessageTypeReadRecInd ); + reportHeaders->AddTypedAddresseeL( TMmsGenUtils::PureAddress( originalHeaders->Sender() ), + EMsvRecipientTo ); + // sender must be insert-address-token because we don't know our own number + // And if there are many recipients we cannot be sure which one is our own number + + // We are through with the original headers + CleanupStack::PopAndDestroy( originalHeaders ); + originalHeaders = NULL; + + TTime now; + now.UniversalTime(); + + TTime y1970( K1970 ); + TTimeIntervalMicroSeconds interval; + // we can't use "seconds from" as it only returns a + // 32 bit signed integer. If fails in 2038. + // "microseconds from" returns a 64 bit signed integer + interval = now.MicroSecondsFrom( y1970 ); + // date in iMmsHeaders() in seconds from 1.1.1970. + reportHeaders->SetDate( ( interval.Int64() ) / KMmsMillion ); + reportHeaders->SetReadStatus( aReadStatus ); + + TMsvId mmsFolderId = iMmsSettings->NotificationFolder(); + cEntry = Session().GetEntryL( mmsFolderId ); + CleanupStack::PushL( cEntry ); + + // We create the entry immediately as complete because we store the data immediately + // If the battery runs out at the wrong moment, garbage collection will throw the + // extra entry away as it is marked as read rec ind. + TMsvEntry entry; + entry.iType = KUidMsvMessageEntry; + entry.iMtm = KUidMsgTypeMultimedia; + entry.SetVisible( ETrue ); + entry.SetInPreparation( EFalse ); + // We set the service as local service to get past the line + // in case sending or receiving is ongoing + entry.iServiceId = KMsvLocalServiceIndexEntryId; + entry.iRelatedId = iServiceId; + entry.iMtmData1 = KMmsMessageReadRecInd; + cEntry->CreateL( entry ); + + TMsvId entryId = entry.Id(); + + cEntry->SetEntryL( entryId ); + + store = cEntry->EditStoreL(); + CleanupStack::PushL( store ); + reportHeaders->StoreL( *store ); + store->CommitL(); + CleanupStack::PopAndDestroy( store ); + store = NULL; + + // These can go now. Our entry is ready to be sent + CleanupStack::PopAndDestroy( cEntry ); + cEntry = NULL; + CleanupStack::PopAndDestroy( reportHeaders ); + reportHeaders = NULL; + + CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection; + CleanupStack::PushL( selection ); + selection->InsertL( 0, entryId ); + + CMsvOperation * op = NULL; + TCommandParameters parameters; // initialized to zero + TCommandParametersBuf paramPack( parameters ); + + op = Session().TransferCommandL( *selection, + EMmsScheduledReadReport, + paramPack, + aCompletionStatus ); + + CleanupStack::PopAndDestroy( selection ); + + return op; + } + +// --------------------------------------------------------- +// CMmsClientMtm::ResponseText +// --------------------------------------------------------- +// +TPtrC CMmsClientMtm::ResponseText() const + { + return iMmsHeaders->ResponseText( ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::ResponseStatus +// --------------------------------------------------------- +// +TInt CMmsClientMtm::ResponseStatus() const + { + return iMmsHeaders->ResponseStatus(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::NumberOfPreviousSenders +// --------------------------------------------------------- +// +TInt CMmsClientMtm::NumberOfPreviousSenders() const + { + return iMmsHeaders->PreviouslySentList().Count(); + } + +// --------------------------------------------------------- +// CMmsClientMtm:: +// --------------------------------------------------------- +// +TPtrC CMmsClientMtm::PreviousSender( TInt aSequenceNumber ) const + { + if ( aSequenceNumber > iMmsHeaders->PreviouslySentList().Count() || + aSequenceNumber < 1 ) + { + return TPtrC(); + } + return iMmsHeaders->PreviouslySentList()[aSequenceNumber - 1]->Sender(); + } + +// --------------------------------------------------------- +// CMmsClientMtm:: +// --------------------------------------------------------- +// +TTime CMmsClientMtm::PreviousSendingDate( TInt aSequenceNumber ) const + { + if ( aSequenceNumber > iMmsHeaders->PreviouslySentList().Count() || + aSequenceNumber < 1 ) + { + return TTime( 0 ); + } + + TInt64 inSeconds; + inSeconds = iMmsHeaders->PreviouslySentList()[aSequenceNumber - 1]->Date(); + + // If not defined in message headers return 0 + if ( inSeconds == 0 ) + { + return TTime(0); + } + + TTime y1970( K1970 ); + // 1970 presented as microseconds after January 1st, 0 AD Gregorian. + TInt64 ms1970 = y1970.Int64(); + + return TTime( ms1970 + ( KMmsMillion * inSeconds ) ); + + } + +// --------------------------------------------------------- +// CMmsClientMtm::MessageReceiveTime +// --------------------------------------------------------- +// +TTime CMmsClientMtm::MessageReceiveTime() const + { + return iMmsHeaders->ReceivingTime(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::MessageTransferSize +// --------------------------------------------------------- +// +TInt CMmsClientMtm::MessageTransferSize() const + { + return iMmsHeaders->MessageSize(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::MessageContentLocation +// --------------------------------------------------------- +// +TPtrC8 CMmsClientMtm::MessageContentLocation() const + { + return iMmsHeaders->ContentLocation(); + } + +//---------------------------------------------------------- +// METHODS FROM BASE CLASS +//---------------------------------------------------------- + +// --------------------------------------------------------- +// CMmsClientMtm::SaveMessageL +// Stores the multimedia message +// --------------------------------------------------------- +// +void CMmsClientMtm::SaveMessageL() + { + // First we should assert that iMsvEntry is not NULL, and panic, if it is + __ASSERT_DEBUG( iMsvEntry, gPanic( EMmsNoCMsvEntrySet )); + // SaveMessageL should only be supported for message entries. + __ASSERT_DEBUG( iMsvEntry->Entry().iType.iUid == KUidMsvMessageEntryValue, + gPanic( EMmsNotAMessageEntry ) ); + + TMsvEntry indexEntry = iMsvEntry->Entry(); + + // Store headers of a multimedia message + + // Because of the way the attachments are handled using the new + // attacment manager, the caller must store and commit the attachments + // either one by one or after all have been added. + // After saving all attachments the edit store used for that purpose + // must be freed. + // The store must be freed because all attachment info and MMS headers + // are saved in the actual message entry, there are no separate + // attachment entries anymore. + + // When a message is saved in client, the possible transaction ID is cleared + // because when the message is changed, it must get a new TID in MMS server + // when it is sent. + iMmsHeaders->SetTidL( TPtrC8() ); + + CMsvStore* store = iMsvEntry->EditStoreL(); + CleanupStack::PushL( store ); + // Check that sufficient disk space available + if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( + &Session().FileSession(), + iMmsHeaders->Size(), + iMessageDrive ) ) + { + User::Leave( KErrDiskFull ); + } + + // Note: Body text not supported. + + iMmsHeaders->StoreL( *store ); + + StoreAttributesL( *store ); + + // Commit the stream store + store->CommitL(); + CleanupStack::PopAndDestroy( store ); + + // Start to update index entry + // If the caller has not set the description, we set it to messge subject - + // if subject is available. + if ( indexEntry.iDescription.Length() == 0 ) + { + indexEntry.iDescription.Set( iMmsHeaders->Subject() ); + } + // The caller must set the message to complete and visible when it is ready: + /* + indexEntry.SetInPreparation( EFalse ); + indexEntry.SetVisible( ETrue ); + indexEntry.iDate.UniversalTime(); + */ + + // attachment size + TInt32 totalSizeOfAllAttachments = AttachmentsSizeL(); + indexEntry.iSize = iMmsHeaders->Size() + totalSizeOfAllAttachments; + + // If there are multiple recipients then set the flag + if (( iMmsHeaders->ToRecipients().Count() + + iMmsHeaders->CcRecipients().Count() + + iMmsHeaders->BccRecipients().Count() ) > 1 ) + { + indexEntry.SetMultipleRecipients( ETrue ); + } + else + { + // clear multiple recipients in case recipients have + // been deleted after the message was saved the last time + indexEntry.SetMultipleRecipients( EFalse ); + } + + // Set iDetails (recipient) + // Check that MT message's details not updated, + // although this should not be possible in UI. + if ( !( indexEntry.iMtmData1 & KMmsMessageMobileTerminated ) ) + { + TPtrC to; + if ( iMmsHeaders->ToRecipients().Count() ) + { + to.Set( TMmsGenUtils::Alias( iMmsHeaders->ToRecipients()[0] ) ); + if ( to.Length() <= 0 ) + { + // If no alias part then set the real address in details + to.Set( iMmsHeaders->ToRecipients()[0] ); + } + } + indexEntry.iDetails.Set( to ); + } + + if ( totalSizeOfAllAttachments > 0 ) + { + indexEntry.SetAttachment( ETrue ); + } + + if ( iAttributes->MdcaCount() > 0 ) + { + indexEntry.iMtmData1 |= KMmsAttributeStreamPresent; + } + else + { + indexEntry.iMtmData1 &= ~KMmsAttributeStreamPresent; + } + + switch ( iMmsHeaders->MessagePriority() ) + { + case KMmsPriorityNormal: + indexEntry.SetPriority( EMsvMediumPriority ); + break; + case KMmsPriorityLow: + indexEntry.SetPriority( EMsvLowPriority ); + break; + case KMmsPriorityHigh: + indexEntry.SetPriority( EMsvHighPriority ); + break; + default: + // if not defined default is normal + indexEntry.SetPriority( EMsvMediumPriority ); + break; + } + + // commit the index changes. + iMsvEntry->ChangeL( indexEntry ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::LoadMessageL +// Loads the multimedia message +// --------------------------------------------------------- +// +void CMmsClientMtm::LoadMessageL() + { + // First we should assert that iMsvEntry is not NULL, and panic, if it is + __ASSERT_DEBUG( iMsvEntry, gPanic( EMmsNoCMsvEntrySet ) ); + // LoadMessageL should only be supported for message entries. + if ( iMsvEntry->Entry().iType.iUid != KUidMsvMessageEntryValue ) + { + iAttributes->Reset(); + iMmsHeaders->Reset(); + iAddresseeList->Reset(); + return; + } + + // Old data must be reset first.... + iAttributes->Reset(); + + // load the correct data + // get read-only message store + CMsvStore* store = iMsvEntry->ReadStoreL(); + CleanupStack::PushL( store ); + + // restore headers of multimedia message + // Attachment info is not restored. + // It makes no sense to cache the attachment info as new attachments + // can be added with the help of the attachment magager without + // informing MMS Client MTM of the additions. + // Caller must use attachment manager to get attachment info. + iMmsHeaders->RestoreL( *store ); + + RestoreAttributesL( *store ); + + CleanupStack::PopAndDestroy( store ); + store = NULL; + + // Build the iAddresseeList up + BuildAddresseeListL(); + + } + +// --------------------------------------------------------- +// CMmsClientmtm::ReplyL +// Send a reply to current message +// --------------------------------------------------------- +// +CMsvOperation* CMmsClientMtm::ReplyL( + TMsvId aDestination, + TMsvPartList aPartList, + TRequestStatus& aCompletionStatus ) + { + + return CMmsMessageOperation::CreateReplyL( + aCompletionStatus, + Session(), + iMsvEntry->EntryId(), + aDestination, + aPartList, + iServiceId ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::ForwardL +// Forward current message +// --------------------------------------------------------- +// +CMsvOperation* CMmsClientMtm::ForwardL( + TMsvId aDestination, + TMsvPartList aPartList, + TRequestStatus& aCompletionStatus ) + { + + return CMmsMessageOperation::CreateForwardL( + aCompletionStatus, + Session(), + iMsvEntry->EntryId(), + aDestination, + aPartList, + iServiceId ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::ValidateMessage +// Validate selected parts of current message +// --------------------------------------------------------- +// +TMsvPartList CMmsClientMtm::ValidateMessage( + TMsvPartList aPartList ) + { + __ASSERT_DEBUG( iMsvEntry, gPanic( EMmsNoCMsvEntrySet )); + + TMsvPartList retVal = 0; + if ( iMsvEntry->Entry().iType.iUid != KUidMsvMessageEntryValue ) + { + // not a message, no part is valid + retVal = aPartList; + } + + if ( aPartList & KMsvMessagePartRecipient ) + { + if ( iAddresseeList->Count() == 0) + { + retVal |= KMsvMessagePartRecipient; + } + else + { + // check the recipient list for valid 'addresses' + for (TInt ii=0; ii < iAddresseeList->Count(); ++ii) + { + TPtrC oneAddress = (*iAddresseeList)[ii]; + TPtrC pureAddress = TMmsGenUtils::PureAddress( oneAddress ); + if ( ( pureAddress.Length() == 0 ) || + !TMmsGenUtils::IsValidAddress( pureAddress, ETrue ) ) + { + retVal |= KMsvMessagePartRecipient; + break; + } + } + } + } + + // all attachments are considered valid - even no attachments + + return retVal; + + } + +// --------------------------------------------------------- +// CMmsClientMtm::Find +// Find text in selected message parts +// --------------------------------------------------------- +// +TMsvPartList CMmsClientMtm::Find( + const TDesC& aTextToFind, + TMsvPartList aPartList ) + { + // The final version will not have a rich text body, but we could + // search for example the originator and description. + + __ASSERT_DEBUG( iMsvEntry, gPanic( EMmsNoCMsvEntrySet ) ); + TMsvPartList foundList = KMsvMessagePartNone; + + TRAP_IGNORE( + { + TMsvEntry entry = iMsvEntry->Entry(); + + CMsvFindText* findText = CMsvFindText::NewL(); + + CleanupStack::PushL( findText ); + + if ( aPartList & KMsvMessagePartRecipient ) + { + // Find from To, Cc and Bcc fields + if ( FindInRecipientL( aTextToFind, + aPartList, iMmsHeaders->ToRecipients(), *findText)) + { + foundList |= KMsvMessagePartRecipient; + } + else if ( FindInRecipientL( aTextToFind, + aPartList, iMmsHeaders->CcRecipients(), *findText )) + { + foundList |= KMsvMessagePartRecipient; + } + else if ( FindInRecipientL( aTextToFind, + aPartList, iMmsHeaders->BccRecipients(), *findText )) + { + foundList |= KMsvMessagePartRecipient; + } + else + { + // keep LINT happy + } + } + + if ( aPartList & KMsvMessagePartOriginator ) + { + if ( findText->FindTextL( aTextToFind, iMmsHeaders->Sender(), + aPartList ) ) + { + foundList |= KMsvMessagePartOriginator; + } + } + + if ( aPartList & KMsvMessagePartDescription ) + { + if ( findText->FindTextL( aTextToFind, entry.iDescription, + aPartList ) ) + { + foundList |= KMsvMessagePartDescription; + } + } + + CleanupStack::PopAndDestroy( findText ); + }); + return foundList; + + } + +// --------------------------------------------------------- +// CMmsClientMtm::AddAddresseeL +// --------------------------------------------------------- +// +void CMmsClientMtm::AddAddresseeL( const TDesC& aRealAddress ) + { + // Add to general list + // When no type is specified, the address will have type "to" + iAddresseeList->AppendL( EMsvRecipientTo, aRealAddress ); + + // Add to "To" recipient list + iMmsHeaders->AddTypedAddresseeL( aRealAddress, EMsvRecipientTo ); + + } + +// --------------------------------------------------------- +// CMmsClientMtm::AddAddresseeL +// --------------------------------------------------------- +// +void CMmsClientMtm::AddAddresseeL( + const TDesC& aRealAddress, + const TDesC& aAlias ) + { + + if ( aAlias.Length() > 0 ) + { + HBufC* buf = TMmsGenUtils::GenerateAddressL( aRealAddress, aAlias ); + CleanupStack::PushL( buf ); + AddAddresseeL( buf->Des() ); + CleanupStack::PopAndDestroy( buf ); + } + else + { + AddAddresseeL( aRealAddress ); + } + } + +// --------------------------------------------------------- +// CMmsClientMtm::AddAddresseeL +// --------------------------------------------------------- +// +void CMmsClientMtm::AddAddresseeL( TMsvRecipientType aType, + const TDesC& aRealAddress ) + { + // Add to general list + // When no type is specified, the address will have type "to" + iAddresseeList->AppendL( aType, aRealAddress ); + + // Add to recipient list + iMmsHeaders->AddTypedAddresseeL( aRealAddress, aType ); + + } + +// --------------------------------------------------------- +// CMmsClientMtm::AddAddresseeL +// --------------------------------------------------------- +// +void CMmsClientMtm::AddAddresseeL( + TMsvRecipientType aType, + const TDesC& aRealAddress, + const TDesC& aAlias ) + { + + if ( aAlias.Length() > 0 ) + { + HBufC* buf = TMmsGenUtils::GenerateAddressL( aRealAddress, aAlias ); + CleanupStack::PushL( buf ); + AddAddresseeL(aType, buf->Des()); + CleanupStack::PopAndDestroy( buf ); + } + else + { + AddAddresseeL( aType, aRealAddress ); + } + } + +// --------------------------------------------------------- +// CMmsClientMtm::RemoveAddressee +// --------------------------------------------------------- +// +void CMmsClientMtm::RemoveAddressee( TInt aIndex ) + { + + if ( iAddresseeList->Count() > aIndex ) + { + // Delete from typed list + TPtrC address = (*iAddresseeList)[ aIndex ]; + iMmsHeaders->RemoveAddressee( address ); + // delete from untyped list + iAddresseeList->Delete( aIndex ); + } + + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetSubjectL +// --------------------------------------------------------- +// +void CMmsClientMtm::SetSubjectL( const TDesC& aSubject ) + { + iMmsHeaders->SetSubjectL( aSubject ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::SubjectL +// --------------------------------------------------------- +// +const TPtrC CMmsClientMtm::SubjectL() const + { + return iMmsHeaders->Subject(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::AddAttachmentL +// --------------------------------------------------------- +// +void CMmsClientMtm::AddAttachmentL( const TDesC& aFilePath, + const TDesC8& aMimeType, TUint aCharset, TRequestStatus& aStatus ) + { + + TInt error = KErrNone; + TUint charset = aCharset; + RFile file; + if ( aMimeType.CompareF( KMmsTextPlain ) == 0 && charset == 0 ) + { + // try to recognize character set + // We trap the recognization process + // If cannot recognize, the result will be 0 and default to us-ascii + TRAP ( error, + { + error = file.Open( Session().FileSession(), aFilePath, + EFileRead|EFileShareReadersOnly ); + if ( error == KErrNone ) + { + CleanupClosePushL( file ); + charset = RecognizeCharSetL( file ); + CleanupStack::PopAndDestroy( &file ); // close file + } + } + ); + } + + // if the attachment character set is unicode, it should be converted to utf-8 + // (see MMS conformance document) + + if ( aMimeType.CompareF( KMmsTextPlain ) == 0 && + ( charset == KMmsUTF16 || + charset == KMmsIso10646Ucs2 || + charset == KMmsUTF16BE || + charset == KMmsUTF16LE ) ) + { + // If we have unicode character set, we must convert the file to utf8 + error = file.Open( Session().FileSession(), aFilePath, + EFileRead|EFileShareReadersOnly ); + if ( error == KErrNone ) + { + CleanupClosePushL( file ); + CMsvStore* store = iMsvEntry->EditStoreL(); + CleanupStack::PushL( store ); + TMsvAttachmentId attaId = 0; + CMmsAttachmentHandler::CreateUTF8TextAttachmentFromFileL( + *store, attaId, file, Session().FileSession(), + Session().CurrentDriveL() ); + store->CommitL(); + CleanupStack::PopAndDestroy( store ); + CleanupStack::PopAndDestroy( &file ); // close file + } + TRequestStatus* status = &aStatus; + aStatus = KRequestPending; + User::RequestComplete( status, error ); + return; + } + else + { + // Disk space is checked in AddFilePathAttachmentL after everything has been initialized + AddFilePathAttachmentL( aFilePath, aMimeType, CMsvAttachment::EMsvFile, aStatus, charset ); + } + } + +// --------------------------------------------------------- +// CMmsClientMtm::AddAttachmentL +// --------------------------------------------------------- +// +void CMmsClientMtm::AddAttachmentL( RFile& aFile, const TDesC8& aMimeType, + TUint aCharset, TRequestStatus& aStatus ) + { + + TInt charset = aCharset; + if ( aMimeType.CompareF( KMmsTextPlain ) == 0 && charset == 0 ) + { + // If no character set defined for a plain text attachment + // we try to recognize the character set. + // But if recoginzation fails, we say 0 (us-ascii) + TRAP_IGNORE ( + { + charset = RecognizeCharSetL( aFile ); + }); + } + + if ( aMimeType.CompareF( KMmsTextPlain ) == 0 ) + { + // If we have unicode character set, we must convert the file to utf8 + if ( ( charset == KMmsUTF16 ) || + ( charset == KMmsIso10646Ucs2 ) || + ( charset == KMmsUTF16BE ) || + ( charset == KMmsUTF16LE ) ) + { + CMsvStore* store = iMsvEntry->EditStoreL(); + CleanupStack::PushL( store ); + TMsvAttachmentId attaId = 0; + CMmsAttachmentHandler::CreateUTF8TextAttachmentFromFileL( *store, + attaId, aFile, Session().FileSession(), + Session().CurrentDriveL() ); + store->CommitL(); + CleanupStack::PopAndDestroy( store ); // store + // We must close the file handle because the attachment manager will also + // close the handle. + // The open file handle is always closed unless the funtion leaves + aFile.Close(); + TRequestStatus* status = &aStatus; + aStatus = KRequestPending; + User::RequestComplete( status, KErrNone ); + return; + } + } + + if( !iAttaWaiter ) + { + iAttaWaiter = CMmsAttachmentWaiter::NewL(); + } + + // store must be the first item allocated because it is the last one to be popped + CMsvStore* store = iMsvEntry->EditStoreL(); + CleanupStack::PushL( store ); + + CMsvAttachment* attachment = CMsvAttachment::NewL( CMsvAttachment::EMsvFile ); + CleanupStack::PushL( attachment ); + + CMsvMimeHeaders* mimeHeaders = CMsvMimeHeaders::NewL(); + CleanupStack::PushL( mimeHeaders ); + + // set the size + TInt size = 0; + User::LeaveIfError( aFile.Size( size ) ); + attachment->SetSize( size ); + + // set the mime-type if provided + if( aMimeType.Length() > 0 ) + { + attachment->SetMimeTypeL( aMimeType ); + TInt position = aMimeType.Find( KMmsSlash8 ); + if ( position > 0 ) + { + mimeHeaders->SetContentTypeL( aMimeType.Left( position ) ); + } + if ( position < aMimeType.Length() - 1 ) + { + mimeHeaders->SetContentSubTypeL( aMimeType.Mid( position + 1 ) ); + } + } + + TFileName fileName; + User::LeaveIfError( aFile.Name( fileName ) ); + attachment->SetAttachmentNameL( fileName ); + + mimeHeaders->SetSuggestedFilenameL( attachment->AttachmentName() ); + mimeHeaders->SetMimeCharset( charset ); + + size += KMmsIndexEntryExtra + mimeHeaders->Size(); + mimeHeaders->StoreL( *attachment ); + + // mime headers have been streamed to CMsvAttachment, they can go now + CleanupStack::PopAndDestroy( mimeHeaders ); + + // Check that sufficient disk space available + if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( + &Session().FileSession(), + size, + iMessageDrive ) ) + { + CleanupStack::PopAndDestroy( attachment ); + User::Leave( KErrDiskFull ); + } + + // attachment is initialised, pass to the attachment manager + MMsvAttachmentManager& manager = store->AttachmentManagerL(); + if ( iAttaWaiter->IsActive() ) + { + // can't start an active operation because already active + User::Leave(KErrInUse); + } + manager.AddAttachmentL( aFile, attachment, iAttaWaiter->iStatus ); + CleanupStack::Pop( attachment ); // ownership passed to manager + // We cannot start waiting before we know that the function we are waiting for + // did not leave. If we become active, and the function leaves, we are in trouble + iAttaWaiter->StartWaitingL( aStatus, store, &manager ); + CleanupStack::Pop( store ); // ownership passed + } + +// --------------------------------------------------------- +// CMmsClientMtm::AddLinkedAttachmentL +// --------------------------------------------------------- +// +void CMmsClientMtm::AddLinkedAttachmentL( const TDesC& aFilePath, + const TDesC8& aMimeType, TUint aCharset, TRequestStatus& aStatus ) + { + TInt error = KErrNone; + TUint charset = aCharset; + if ( aMimeType.CompareF( KMmsTextPlain ) == 0 && aCharset == 0 ) + { + // try to recognize character set + // We trap the recognization process + // If cannot recognize, the result will be 0 and default to us-ascii + TRAP ( error, + { + RFile file; + error = file.Open( Session().FileSession(), aFilePath, + EFileRead|EFileShareReadersOnly); + if ( error == KErrNone ) + { + CleanupClosePushL( file ); + charset = RecognizeCharSetL( file ); + CleanupStack::PopAndDestroy( &file ); // close file + } + } + ); + } + // Linked files cannot be converted to utf8. They must be sent as is no + // matter what the character set is. + + // Disk space is checked in AddFilePathAttachmentL after everything has + // been initialized. + + + if ( aMimeType.CompareF( KMmsTextPlain ) == 0 && + ( charset == KMmsUTF16 || + charset == KMmsIso10646Ucs2 || + charset == KMmsUTF16LE || + charset == KMmsUTF16BE ) ) + { + AddAttachmentL( aFilePath, aMimeType, charset, aStatus ); + } + else + { + AddFilePathAttachmentL( aFilePath, aMimeType, + CMsvAttachment::EMsvLinkedFile, aStatus, charset ); + } + } + +// --------------------------------------------------------- +// CMmsClientMtm::AddEntryAsAttachmentL +// --------------------------------------------------------- +// +void CMmsClientMtm::AddEntryAsAttachmentL( TMsvId /*aAttachmentId*/, + TRequestStatus& /*aStatus*/ ) + { + User::Leave( KErrNotSupported ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::CreateAttachmentL +// --------------------------------------------------------- +// +void CMmsClientMtm::CreateAttachmentL( const TDesC& aFileName, + RFile& aAttachmentFile, const TDesC8& aMimeType, + TUint aCharset, TRequestStatus& aStatus ) + { + // Character set cannot be checked here because the file does not exist yet + // The caller gets an open file handle and is supposed to write data into + // the file. + if( !iAttaWaiter ) + { + iAttaWaiter = CMmsAttachmentWaiter::NewL(); + } + + // store must be the first item allocated because it is the last one to be popped + CMsvStore* store = iMsvEntry->EditStoreL(); + CleanupStack::PushL( store ); + + CMsvAttachment* attachmentInfo = + CMsvAttachment::NewL( CMsvAttachment::EMsvFile ); + CleanupStack::PushL( attachmentInfo ); + + CMsvMimeHeaders* mimeHeaders = CMsvMimeHeaders::NewL(); + CleanupStack::PushL( mimeHeaders ); + + attachmentInfo->SetAttachmentNameL( aFileName ); + + // set the mime-type if provided + if( aMimeType.Length() > 0 ) + { + attachmentInfo->SetMimeTypeL( aMimeType ); + TInt position = aMimeType.Find( KMmsSlash8 ); + if ( position > 0 ) + { + mimeHeaders->SetContentTypeL( aMimeType.Left( position ) ); + } + if ( position < aMimeType.Length() - 1 ) + { + mimeHeaders->SetContentSubTypeL( aMimeType.Mid( position + 1 ) ); + } + } + + // save the character set + mimeHeaders->SetMimeCharset( aCharset ); + + mimeHeaders->SetSuggestedFilenameL( attachmentInfo->AttachmentName() ); + + TInt size = 0; + size = KMmsIndexEntryExtra + mimeHeaders->Size(); + mimeHeaders->StoreL( *attachmentInfo ); + + // mime headers have been streamed to CMsvAttachment, they can go now + CleanupStack::PopAndDestroy( mimeHeaders ); + + // Check that sufficient disk space available + if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( + &Session().FileSession(), + size, + iMessageDrive ) ) + { + CleanupStack::PopAndDestroy( attachmentInfo ); + User::Leave( KErrDiskFull ); + } + + MMsvAttachmentManager& manager = store->AttachmentManagerL(); + if ( iAttaWaiter->IsActive() ) + { + // can't start an active operation because already active + User::Leave(KErrInUse); + } + manager.CreateAttachmentL( aFileName, aAttachmentFile, attachmentInfo, + iAttaWaiter->iStatus ); + CleanupStack::Pop( attachmentInfo ); // ownership passed to manager + iAttaWaiter->StartWaitingL( aStatus, store, &manager ); + CleanupStack::Pop( store ); // ownership passed + } + +// --------------------------------------------------------- +// CMmsClientMtm::CancelAttachmentOperation +// --------------------------------------------------------- +// +void CMmsClientMtm::CancelAttachmentOperation() + { + + if ( iAttaWaiter ) + { + iAttaWaiter->Cancel(); + delete iAttaWaiter; + iAttaWaiter = NULL; + } + } + +// --------------------------------------------------------- +// CMmsClientMtm::CreateAttachment2L +// --------------------------------------------------------- +// +void CMmsClientMtm::CreateAttachment2L( + CMsvStore& aStore, + RFile& aFile, + TDesC8& aMimeType, + CMsvMimeHeaders& aMimeHeaders, + CMsvAttachment* aAttachmentInfo, + TMsvAttachmentId& aAttaId) + { + _LIT8( KMmsText, "text" ); + _LIT8( KMmsPlain, "plain" ); + + if ( ( aMimeType.CompareF( KMmsTextPlain ) == 0 || + ( aMimeHeaders.ContentType().CompareF( KMmsText ) == 0 && + aMimeHeaders.ContentSubType().CompareF( KMmsPlain ) == 0 ) ) && + aMimeHeaders.MimeCharset() == 0 ) + { + // If no character set defined for a plain text attachment + // we try to recognize the character set. + // But if recoginzation fails, we say 0 (us-ascii) + TInt charset = 0; + TRAP_IGNORE ( + { + charset = RecognizeCharSetL( aFile ); + }); + aMimeHeaders.SetMimeCharset( charset ); + } + + return CMmsAttachmentHandler::CreateAttachmentL( + aStore, + aFile, + Session().FileSession(), + Session().CurrentDriveL(), + aMimeType, + aMimeHeaders, + aAttachmentInfo, + aAttaId ); + + } + +// --------------------------------------------------------- +// CMmsClientMtm::CreateTextAttachmentL +// --------------------------------------------------------- +// +void CMmsClientMtm::CreateTextAttachmentL( + CMsvStore& aStore, + TMsvAttachmentId& aAttachmentId, + const TDesC& aText, + const TDesC& aFile, + TBool aConvertParagraphSeparator ) + { + + CMmsAttachmentHandler::CreateTextAttachmentL( aStore, + aAttachmentId, + aText, + aFile, + Session().FileSession(), + Session().CurrentDriveL(), + aConvertParagraphSeparator ); + + } + +// --------------------------------------------------------- +// CMmsClientMtm::CreateMessageL +// --------------------------------------------------------- +// +void CMmsClientMtm::CreateMessageL( + TMsvId aServiceId ) + { + // Check that sufficient disk space available + // for index entry + if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( + &Session().FileSession(), + KMmsIndexEntryExtra, + iMessageDrive ) ) + { + // we use standard error code here + User::Leave( KErrDiskFull ); + } + + // just call the base class function + CBaseMtm::CreateMessageL( aServiceId ); + + iMmsHeaders->Reset( iMmsSettings ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::BioTypeChangedL +// --------------------------------------------------------- +// +void CMmsClientMtm::BioTypeChangedL( TUid /*aBioTypeUid*/ ) + { + // Do nothing. MMS does not support BIO type. + } + +// --------------------------------------------------------- +// CMmsClientMtm::DefaultServiceL +// --------------------------------------------------------- +// +TMsvId CMmsClientMtm::DefaultServiceL() const + { + // Override base implementation so that we always use MMS service + // even when called by Postcard or Audio Message which have different MTM tyoe + + if ( iServiceId != KMsvNullIndexEntryId ) + { + return iServiceId; + } + + // Create a new entry, showing invisible entries (because the service entry is invisible) + + TMsvSelectionOrdering ordering( KMsvNoGrouping, EMsvSortByNone, ETrue ); + CMsvEntry* entry = CMsvEntry::NewL( iOwnSession, KMsvRootIndexEntryId, ordering ); + CleanupStack::PushL( entry ); + + CMsvEntrySelection *sel=entry->ChildrenWithMtmL( KUidMsgTypeMultimedia ); + CleanupStack::PushL( sel ); + if( sel->Count() == 0 ) + { + User::Leave(KErrNotFound); + } + TMsvId service=sel->At( 0 ); + CleanupStack::PopAndDestroy( sel ); + CleanupStack::PopAndDestroy( entry ); + return service; + } + +// --------------------------------------------------------- +// CMmsClientMtm::RemoveDefaultServiceL +// --------------------------------------------------------- +// +void CMmsClientMtm::RemoveDefaultServiceL() + { + // not supported + } + +// --------------------------------------------------------- +// CMmsClientMtm::ChangeDefaultServiceL +// --------------------------------------------------------- +// +void CMmsClientMtm::ChangeDefaultServiceL( const TMsvId& /*aService*/ ) + { + // not supported + } + +// --------------------------------------------------------- +// CMmsClientMtm::QueryCapability +// --------------------------------------------------------- +// +TInt CMmsClientMtm::QueryCapability( + TUid aCapability, + TInt& aResponse ) + { + TInt error = KErrNone; + switch ( aCapability.iUid ) + { + // Supported: + case KUidMtmQueryMaxTotalMsgSizeValue: + aResponse = KMaxTInt; + break; + case KUidMsvMtmQueryEditorUidValue: + aResponse = KUidMsgMmsEditor; + break; + case KUidMtmQueryMaxRecipientCountValue: + // According to conformance document we must support at least 20 + aResponse = -1; // unlimited number + break; + case KUidMtmQuerySendAsMessageSendSupportValue: + aResponse = ETrue; + break; + case KUidMtmQuerySupportSubjectValue: + case KUidMtmQuerySupportAttachmentsValue: + case KUidMtmQueryCanSendMsgValue: + case KUidMtmQueryCanReceiveMsgValue: + case KUidMtmQuerySupportsRecipientTypeValue: + // returns KErrNone + break; + // All others - Not Supported: + default: + error = KErrNotSupported; + break; + } + return error; + + } + +// --------------------------------------------------------- +// CClientMtm::InvokeSyncFunctionL +// --------------------------------------------------------- +// +void CMmsClientMtm::InvokeSyncFunctionL( + TInt /*aFunctionId*/, + const CMsvEntrySelection& /*aSelection*/, + TDes8& /*aParameter*/ ) + { + + User::Leave( KErrNotSupported ); + + } + +// --------------------------------------------------------- +// CMmsClientMtm::InvokeAsyncFunctionL +// --------------------------------------------------------- +// +CMsvOperation* CMmsClientMtm::InvokeAsyncFunctionL( + TInt aFunctionId, + const CMsvEntrySelection& aSelection, + TDes8& aParameter, + TRequestStatus& aCompletionStatus ) + { + + CMsvOperation* op = NULL; + + if ( aSelection.Count() == 0 ) + { + User::Leave( KErrArgument ); + } + + // make a copy of the selection just in case + CMsvEntrySelection* selection = aSelection.CopyL(); + CleanupStack::PushL( selection ); + + // Change service id to related id + // for the scheduled commands + CMsvEntry* cEntry = NULL; + TInt error = KErrNone; + + if ( aFunctionId == EMmsScheduledSend || + aFunctionId == EMmsScheduledReceive || + aFunctionId == EMmsScheduledReceiveForced || + aFunctionId == EMmsDeleteSchedule || + aFunctionId == EMmsScheduledForward || + aFunctionId == EMmsScheduledNotificationDelete || + aFunctionId == KMTMStandardFunctionsSendMessage ) + { + TInt j = 0; + TInt i; + cEntry = Session().GetEntryL( KMsvRootIndexEntryId ); + CleanupStack::PushL( cEntry ); + + if ( aSelection.At( 0 ) == iServiceId ) + { + // skip service + j++; + } + + for ( i = aSelection.Count() - 1; i >=j; i-- ) + { + TRAP( error, + { + cEntry->SetEntryL( aSelection.At( i ) ); + TMsvEntry entry = cEntry->Entry(); + // check first to be sure you don't lose the original + // service id + if ( entry.iServiceId != KMsvLocalServiceIndexEntryId ) + { + entry.iRelatedId = entry.iServiceId; + } + entry.iServiceId = KMsvLocalServiceIndexEntryId; + cEntry->ChangeL( entry ); + }); + if ( error == KErrNotFound ) + { + selection->Delete( i ); + } + } + + CleanupStack::PopAndDestroy( cEntry ); + cEntry = NULL; + } + + if ( aFunctionId == KMTMStandardFunctionsSendMessage && selection->Count() > 0 ) + { + // This is the SendAs send command. Ignore parameter + TCommandParameters parameters; // initialized to zero + TCommandParametersBuf paramPack( parameters ); + // Move the messages to OUTBOX synchronously + cEntry = Session().GetEntryL( KMsvLocalServiceIndexEntryIdValue ); + CleanupStack::PushL( cEntry ); + cEntry->SetEntryL( selection->At( 0 ) ); + TMsvId currentParent = cEntry->Entry().Parent(); + TMsvLocalOperationProgress progress; + if ( currentParent != KMsvGlobalOutBoxIndexEntryId ) + { + cEntry->MoveL( *selection, KMsvGlobalOutBoxIndexEntryId, progress ); + } + CleanupStack::PopAndDestroy( cEntry ); + cEntry = NULL; + } + + if ( selection->Count() == 0 ) + { + // we are given a selection of entries that were not found. + User::Leave( KErrNotFound ); + } + + // + // Pass all commands onto the server MTM + // + if ( aFunctionId == KMTMStandardFunctionsSendMessage ) + { + // no need to put op on cleanup stack because + // its ownership will be transferred to caller in a moment + op = CMmsSendMessageOperation::NewL( Session(), + *selection, + aParameter, + aCompletionStatus ); + } + else + { + op = Session().TransferCommandL( + *selection, aFunctionId, aParameter, aCompletionStatus ); + } + CleanupStack::PopAndDestroy( selection ); + return op; + } + +// --------------------------------------------------------- +// CMmsClientMtm::ListNotificationsInInboxL +// --------------------------------------------------------- +// +CMsvEntrySelection* CMmsClientMtm::ListNotificationsInInboxL() + { + CMsvEntry* cEntry = Session().GetEntryL( KMsvGlobalInBoxIndexEntryId ); + CleanupStack::PushL( cEntry ); + + CMsvEntrySelection* notifications = + cEntry->ChildrenWithMtmL( KUidMsgMMSNotification ); + CleanupStack::PushL( notifications ); + + // Count only notifications that are free for a new operation + for ( TInt i = notifications->Count() - 1 ; i >= 0; i-- ) + { + TMsvId notifId = notifications->At( i ); + cEntry->SetEntryL( notifId ); + + TMsvEntry tEntry = cEntry->Entry(); + if ( tEntry.iMtmData2 & KMmsNewOperationForbidden ) + { + // Delete notification from the notifications array. + notifications->Delete( i ); + } + } + + notifications->Compress(); + CleanupStack::Pop( notifications ); // ownership transferred to caller + CleanupStack::PopAndDestroy( cEntry ); + return notifications; + } + +// --------------------------------------------------------- +// CMmsClientMtm::ContextEntrySwitched +// --------------------------------------------------------- +// +void CMmsClientMtm::ContextEntrySwitched() + { + // Context change notification. + // Reset data. + + // Note: Body text reset would be here if supported. + + iAddresseeList->Reset(); + iMmsHeaders->Reset( iMmsSettings ); + iFetchAll = EFalse; + iFetchOverride = ETrue; + iAttributes->Reset(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::HandleEntryEventL +// --------------------------------------------------------- +// +void CMmsClientMtm::HandleEntryEventL( + TMsvEntryEvent /*aEvent*/, + TAny* /*arg1*/, + TAny* /*arg2*/, + TAny* /*arg3*/ ) + { + // No operation + } + +// --------------------------------------------------------- +// CMmsClientMtm::ConstructL +// --------------------------------------------------------- +// +void CMmsClientMtm::ConstructL() + { + // First loading settings + iMmsSettings = CMmsSettings::NewL(); + iMmsSettings->LoadSettingsL(); + // Get the base values to detect changes + iHomeMode = iMmsSettings->ReceivingModeHome(); + iRoamingMode = iMmsSettings->ReceivingModeForeign(); + iAccessPointCount = iMmsSettings->AccessPointCount(); + + iMessageDrive = EDriveC; + TInt error = KErrNone; + + TRAP ( error, { iMessageDrive = Session().CurrentDriveL(); } ); + + if ( error != KErrNone ) + { + // if cannot ask, use default + iMessageDrive = EDriveC; + } + + // if no service, creating one + TMsvId tempServiceId = KMsvNullIndexEntryId; + TRAP( error, tempServiceId = DefaultServiceL() ) + { + if ( error == KErrNotFound ) + { + tempServiceId = KMsvNullIndexEntryId; + } + } + + // service id is set after call to DefaultServiceL(), otherwise + // DefaultServiceL() will just return iServiceId + iServiceId = iMmsSettings->Service(); + if ( iServiceId == KMsvNullIndexEntryId || + iServiceId != tempServiceId ) + { + // If there was no default service, a new one must be created. + + // If the service id saved in the settings differs from + // the one read from disk, we call create service. + // The create service function should check the actual + // values of MMS service and MMS private folders and + // ensure that the values in central repository and mail store match. + + // Check that sufficient disk space available + // for service entry + if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( + &Session().FileSession(), + KMmsIndexEntryExtra, // Service entry has no extra data + iMessageDrive ) ) + { + // we use standard error code here + User::Leave( KErrDiskFull ); + } + // creates new service entry + notification and mmbox folder entries + iMmsSettings->CreateNewServiceL( Session() ); + // Save settings is not needed - service creation saves the settings. + iServiceId = iMmsSettings->Service(); + } + + iMmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() ); + + // Address alias separators no longer read from resoure. + // Standard MIME separators < and > always used. + + iAttributes = new(ELeave) CDesCArrayFlat( KMmsAttributeArrayGranularity ); + + // Set the original context to the service entry + SwitchCurrentEntryL( iServiceId ); + + } + +// --------------------------------------------------------- +// CMmsClientMtm::ValidateService +// --------------------------------------------------------- +// +TInt CMmsClientMtm::ValidateService( TMsvId aServiceId ) + { + TInt error = KErrNone; + // There should be only one service, + // and it must match with the one that is in settings + if( aServiceId != iMmsSettings->Service() ) + { + return KErrNotFound; + } + + // Check settings + error = iMmsSettings->ValidateSettings(); + return error; + } + +// --------------------------------------------------------- +// CMmsClientMtm::MessageSize +// --------------------------------------------------------- +// +TInt32 CMmsClientMtm::MessageSize() + { + // First we should assert that iMsvEntry is not NULL, and panic, if it is + __ASSERT_DEBUG( iMsvEntry, gPanic( EMmsNoCMsvEntrySet )); + TUint size = 0; + TRAP_IGNORE({size = AttachmentsSizeL() + iMmsHeaders->Size();} ); + return size; + } + +// --------------------------------------------------------- +// CMmsClientMtm::SetMessageDescriptionL +// --------------------------------------------------------- +// +void CMmsClientMtm::SetMessageDescriptionL( const TDesC& aText ) + { + // First we should assert that iMsvEntry is not NULL, and panic, if it is + __ASSERT_DEBUG( iMsvEntry, gPanic( EMmsNoCMsvEntrySet )); + TMsvEntry entry = iMsvEntry->Entry(); + entry.iDescription.Set( aText ); + iMsvEntry->ChangeL( entry ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::AddAttributeL +// --------------------------------------------------------- +// +void CMmsClientMtm::AddAttributeL( const TDesC& aName, const TDesC& aValue ) + { + if ( aName.Length() == 0 || aValue.Length() == 0 ) + { + User::Leave( KErrArgument ); + } + TMmsGenUtils::AddAttributeL( aName, aValue, *iAttributes ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::GetAttributeL +// --------------------------------------------------------- +// +TPtrC CMmsClientMtm::GetAttributeL( const TDesC& aName ) + { + if ( aName.Length() == 0 ) + { + User::Leave( KErrArgument ); + } + return TMmsGenUtils::GetAttributeL( aName, *iAttributes ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::FindAttribute +// --------------------------------------------------------- +// +TBool CMmsClientMtm::FindAttribute( const TDesC& aName ) + { + if ( aName.Length() == 0 ) + { + return EFalse; + } + return TMmsGenUtils::FindAttribute( aName, *iAttributes ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::DeleteAttribute +// --------------------------------------------------------- +// +void CMmsClientMtm::DeleteAttribute( const TDesC& aName ) + { + if ( aName.Length() == 0 ) + { + return; + } + TMmsGenUtils::DeleteAttribute( aName, *iAttributes ); + } + +// --------------------------------------------------------- +// CMmsClientMtm::ResetAttributes +// --------------------------------------------------------- +// +void CMmsClientMtm::ResetAttributes() + { + iAttributes->Reset(); + } + +// --------------------------------------------------------- +// CMmsClientMtm::BuildAddresseeListL +// --------------------------------------------------------- +// +void CMmsClientMtm::BuildAddresseeListL() + { + + iAddresseeList->Reset(); + + const CDesCArray& array1 = iMmsHeaders->ToRecipients(); + const CDesCArray& array2 = iMmsHeaders->CcRecipients(); + const CDesCArray& array3 = iMmsHeaders->BccRecipients(); + + BuildAddresseeListL( array1, EMsvRecipientTo ); + BuildAddresseeListL( array2, EMsvRecipientCc ); + BuildAddresseeListL( array3, EMsvRecipientBcc ); + + } + +// --------------------------------------------------------- +// CMmsClientMtm::BuildAddresseeListL +// --------------------------------------------------------- +// +void CMmsClientMtm::BuildAddresseeListL( + const CDesCArray& aArray, TMsvRecipientType aValue ) + { + + TInt size; + size = aArray.Count(); + for ( TInt i=0; i < size; i++ ) + { + iAddresseeList->AppendL( aValue, aArray[i] ); + } + } + +// --------------------------------------------------------- +// CMmsClientMtm::AttachmentsSizeL +// --------------------------------------------------------- +// +TInt32 CMmsClientMtm::AttachmentsSizeL() + { + TInt32 size = 0; + // We need to have store. If the caller is keeping edit store open, + // this function leaves. + // That makes sense, because in that case the user might have + // uncommitted attachments, and the total size would be incorrect anyway. + CMsvStore* store = iMsvEntry->ReadStoreL(); + CleanupStack::PushL( store ); + size = CMmsAttachmentHandler::AttachmentsSizeL( *store ); + CleanupStack::PopAndDestroy( store ); + store = NULL; + return size; + } + +// --------------------------------------------------------- +// CMmsClientMtm::ListMmsFolderNotificationsL() +// --------------------------------------------------------- +// +CMsvEntrySelection* CMmsClientMtm::ListMmsFolderNotificationsL() + { + + // list notifications in private invisible folder + + TMsvId notificationParent = iMmsSettings->NotificationFolder(); + + CMsvEntrySelection* notifications = NULL; + if ( notificationParent == KMsvNullIndexEntryId ) + { + notifications = new ( ELeave ) CMsvEntrySelection(); + return notifications; // empty selection + } + + CMsvEntry* cEntry = NULL; + cEntry = Session().GetEntryL( notificationParent ); + CleanupStack::PushL( cEntry ); + + // show invisible entries + cEntry->SetSortTypeL( TMsvSelectionOrdering( KMsvNoGrouping, + EMsvSortByNone, ETrue ) ); + notifications = cEntry->ChildrenWithMtmL( KUidMsgTypeMultimedia ); + CleanupStack::PushL( notifications ); + + // strip off stuff other than notifications + // We are handling the invisible MMS folder now + // There may be delivery reports or binary notifications besides + // the normal notifications + + for ( TInt i = notifications->Count() - 1; i >= 0; i-- ) + { + cEntry->SetEntryL( notifications->At( i )); + + TMsvEntry myEntry = cEntry->Entry(); + if ( !( ( myEntry.iMtmData1 & KMmsMessageTypeMask ) == + KMmsMessageMNotificationInd ) ) + { + // this is not notification + notifications->Delete( i ); + } + } + + notifications->Compress(); + + CleanupStack::Pop( notifications ); // ownership transferred to caller + CleanupStack::PopAndDestroy( cEntry ); + + return notifications; + + } + +// --------------------------------------------------------- +// CMmsClientMtm::ListInboxNotificationsL() +// --------------------------------------------------------- +// +CMsvEntrySelection* CMmsClientMtm::ListInboxNotificationsL() + { + CMsvEntry* cEntry = NULL; + cEntry = Session().GetEntryL( KMsvGlobalInBoxIndexEntryId ); + CleanupStack::PushL( cEntry ); + + CMsvEntrySelection* notifications = new( ELeave )CMsvEntrySelection; + CleanupStack::PushL( notifications ); + + // Notifications from inbox - but not in offline state if the user has not + // initiated the fetch (iFetchOeverride = ETrue) + // If the user initiates the fetch in offline mode, the entry goes to + // failed state because the use must see why the fetching fails. + // CMmsNotificationClientMtm overrides the FetchAllL function so that + // we should get here only when the receiving mode changes. + if ( iFetchOverride || TMmsGenUtils::NetworkOperationsAllowed() ) + { + CMsvEntrySelection* notificationsInInbox = ListNotificationsInInboxL(); + CleanupStack::PushL( notificationsInInbox ); + + // The readOnly flag has to be set on for notifications in inbox + // in order to schedule notifications. + for ( TInt j = notificationsInInbox->Count() - 1; j >= 0; j-- ) + { + cEntry->SetEntryL( notificationsInInbox->At( j ) ); + TMsvEntry entry = cEntry->Entry(); + entry.SetReadOnly( EFalse ); + cEntry->ChangeL( entry ); + + notifications->AppendL( notificationsInInbox->At( j ) ); + } + + CleanupStack::PopAndDestroy( notificationsInInbox ); + } + + CleanupStack::Pop( notifications ); // ownership transferred to caller + CleanupStack::PopAndDestroy( cEntry ); + + return notifications; + } + +// --------------------------------------------------------- +// CMmsClientMtm::FetchAllFromInboxL +// --------------------------------------------------------- +// +CMsvOperation* CMmsClientMtm::FetchAllFromInboxL( TRequestStatus& aCompletionStatus, + TBool aForced ) + { + + iFetchOverride = aForced; + + CMsvEntrySelection* selection = ListInboxNotificationsL(); + CleanupStack::PushL( selection ); + + if ( selection->Count() == 0 ) + { + CleanupStack::PopAndDestroy( selection ); + TPckgC < TMsvId > progress = 0; + aCompletionStatus = KRequestPending; + return CMsvCompletedOperation::NewL( Session(), Type(), progress, + KMsvLocalServiceIndexEntryId, aCompletionStatus ); + } + + TCommandParameters parameters; // initialized to zero + TCommandParametersBuf paramPack( parameters ); + + CMsvOperation* op = NULL; + if ( iFetchOverride ) + { + op = InvokeAsyncFunctionL( + EMmsScheduledReceiveForced, + *selection, + paramPack, + aCompletionStatus ); + } + else + { + op = InvokeAsyncFunctionL( + EMmsScheduledReceive, + *selection, + paramPack, + aCompletionStatus ); + // reset override to default value + iFetchOverride = ETrue; + } + + CleanupStack::PopAndDestroy( selection ); + return op; + } + + +// --------------------------------------------------------- +// CMmsClientMtm::ConvertUTCDateToLocal +// --------------------------------------------------------- +// +/* +TInt64 CMmsClientMtm::ConvertUTCDateToLocal( TInt64 aDate ) const + { + + TLocale locale; + locale.Refresh(); + TInt64 localDate; + TTimeIntervalSeconds universalTimeOffset( locale.UniversalTimeOffset() ); + + localDate = aDate + universalTimeOffset.Int(); + + if ( locale.QueryHomeHasDaylightSavingOn() ) + { + TTimeIntervalSeconds daylightSaving( 60 * 60 ); + localDate += daylightSaving.Int(); + } + + return localDate; + + } +*/ + +// --------------------------------------------------------- +// CMmsClientMtm::FindInRecipientL +// --------------------------------------------------------- +// +TBool CMmsClientMtm::FindInRecipientL( + const TDesC& aTextToFind, + TMsvPartList aPartlist, + const CDesCArray& aRecipients, + CMsvFindText& aFindText ) + { + TInt count = aRecipients.Count(); + TBool found = EFalse; + for (TInt i=0; i < count; i++ ) + { + // Check alias and real address parts + // separately. Otherwise separator character could + // spoil the check. + if ( aFindText.FindTextL( aTextToFind, + TMmsGenUtils::Alias( aRecipients[i] ), aPartlist ) ) + { + found = ETrue; + break; + } + else if ( aFindText.FindTextL( aTextToFind, + TMmsGenUtils::PureAddress( aRecipients[i] ), aPartlist ) ) + { + found = ETrue; + break; + } + else + { + // keep LINT happy + } + } + return found; + } + +// --------------------------------------------------------- +// CMmsClientMtm::AddFilePathAttachmentL +// --------------------------------------------------------- +// +void CMmsClientMtm::AddFilePathAttachmentL( + const TDesC& aFilePath, + const TDesC8& aMimeType, + CMsvAttachment::TMsvAttachmentType aType, + TRequestStatus& aStatus, + const TUint aCharacterSet /* = 0 */ ) + { + __ASSERT_DEBUG( aType != CMsvAttachment::EMsvMessageEntry, + User::Invariant() ); + + if( !iAttaWaiter ) + { + iAttaWaiter = CMmsAttachmentWaiter::NewL(); + } + + // store must be the first item allocated because it is the last one to be popped + CMsvStore* store = iMsvEntry->EditStoreL(); + CleanupStack::PushL( store ); + + CMsvAttachment* attachment = CMsvAttachment::NewL( aType ); + CleanupStack::PushL( attachment ); + + CMsvMimeHeaders* mimeHeaders = CMsvMimeHeaders::NewL(); + CleanupStack::PushL( mimeHeaders ); + + // set the size + TEntry fileEntry; + RFs& fs = Session().FileSession(); + User::LeaveIfError( fs.Entry( aFilePath, fileEntry ) ); + attachment->SetSize( fileEntry.iSize ); + + // set attachment name + TParse fileNameParser; + User::LeaveIfError( fileNameParser.Set( aFilePath, NULL, NULL) ); + + attachment->SetAttachmentNameL( fileNameParser.NameAndExt() ); + // set the mime-type if provided + if( aMimeType.Length() > 0 ) + { + attachment->SetMimeTypeL( aMimeType ); + TInt position = aMimeType.Find( KMmsSlash8 ); + if ( position > 0 ) + { + mimeHeaders->SetContentTypeL( aMimeType.Left( position ) ); + } + if ( position < aMimeType.Length() - 1 ) + { + mimeHeaders->SetContentSubTypeL( aMimeType.Mid( position + 1 ) ); + } + } + + mimeHeaders->SetSuggestedFilenameL( attachment->AttachmentName() ); + + mimeHeaders->SetMimeCharset( aCharacterSet ); + mimeHeaders->StoreL( *attachment ); + + TInt diskSpace = 0; + diskSpace = KMmsIndexEntryExtra + mimeHeaders->Size(); + + // mime headers have been streamed to CMsvAttachment, they can go now + CleanupStack::PopAndDestroy( mimeHeaders ); + + // now we know how much disk space we need + if ( aType == CMsvAttachment::EMsvFile ) + { + diskSpace += attachment->Size(); + } + + // Check that sufficient disk space available + if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( + &Session().FileSession(), + diskSpace, + iMessageDrive ) ) + { + // we use standard error code here + CleanupStack::PopAndDestroy( attachment ); + User::Leave( KErrDiskFull ); + } + + // attachment is initialised, pass to the attachment manager + MMsvAttachmentManager& manager = store->AttachmentManagerL(); + if ( iAttaWaiter->IsActive() ) + { + // can't start an active operation because already active + User::Leave(KErrInUse); + } + switch( aType ) + { + case CMsvAttachment::EMsvLinkedFile: + manager.AddLinkedAttachmentL( aFilePath, attachment, + iAttaWaiter->iStatus ); + break; + default: // CMsvAttachment::EMsvFile + manager.AddAttachmentL( aFilePath, attachment, + iAttaWaiter->iStatus ); + break; + } + + CleanupStack::Pop( attachment ); // ownership passed to manager + // We cannot start waiting before we know that the function we are waiting for + // did not leave. If we become active, and the function leaves, we are in trouble + iAttaWaiter->StartWaitingL( aStatus, store, &manager ); + CleanupStack::Pop( store ); // ownership passed to iAttaWaiter + } + + +// --------------------------------------------------------- +// CMmsClientMtm::StoreAttributesL +// --------------------------------------------------------- +// +void CMmsClientMtm::StoreAttributesL( CMsvStore& aStore ) + { + + if ( iAttributes->MdcaCount() == 0 ) + { + if ( aStore.IsPresentL( KUidMmsAttributeStream ) ) + { + aStore.RemoveL( KUidMmsAttributeStream ); + } + return; + } + + RMsvWriteStream writeStream; + // pushes 'writeStream' to the stack + writeStream.AssignLC( aStore, KUidMmsAttributeStream ); + + writeStream.WriteInt32L( iAttributes->MdcaCount() ); + + TInt i; + for ( i = 0; i < iAttributes->MdcaCount(); i++ ) + { + writeStream << (*iAttributes)[i]; + } + + writeStream.CommitL(); + writeStream.Close(); + CleanupStack::PopAndDestroy( &writeStream ); // close writeStream + } + +// --------------------------------------------------------- +// CMmsClientMtm::RestoreAttributesL +// --------------------------------------------------------- +// +void CMmsClientMtm::RestoreAttributesL( CMsvStore& aStore ) + { + iAttributes->Reset(); + if ( !aStore.IsPresentL( KUidMmsAttributeStream ) ) + { + return; + } + + RMsvReadStream readStream; + // pushes readStream to clenaup stack + readStream.OpenLC( aStore, KUidMmsAttributeStream ); + + TInt count = 0; + + count = readStream.ReadInt32L(); + TInt i; + HBufC* desBuffer; + + for ( i = 0; i < count; i++ ) + { + desBuffer = HBufC::NewLC( readStream, KMaxTInt ); + iAttributes->AppendL( *desBuffer ); + CleanupStack::PopAndDestroy( desBuffer ); + } + + readStream.Close(); + CleanupStack::PopAndDestroy( &readStream ); // close readStream + } + +// --------------------------------------------------------- +// CMmsClientMtm::RecognizeCharSetL +// --------------------------------------------------------- +// +TUint CMmsClientMtm::RecognizeCharSetL( RFile& aFile ) + { + TUint charset = 0; + + // Use CMsgTextUtils for character conversion + CMsgTextUtils* msgTextUtils = CMsgTextUtils::NewL( Session().FileSession() ); + CleanupStack::PushL( msgTextUtils ); + + charset = msgTextUtils->RecognizeCharSetL( Session().FileSession(), aFile ); + if ( charset == 0 ) + { + charset = KMmsUTF16; // utf16 with explicit byte order mark + CleanupStack::PopAndDestroy( msgTextUtils ); + return charset; // unicode little endian or big endian + } + + charset = msgTextUtils->CharconvIdToMibIdL( charset ); + CleanupStack::PopAndDestroy( msgTextUtils ); + return charset; + } + + + +// --------------------------------------------------------- +// CMmsClientMtm:: +// --------------------------------------------------------- +// + + +// ================= OTHER EXPORTED FUNCTIONS ============== + +// +// --------------------------------------------------------- +// gPanic implements +// panic function, should be used by debug version only +// +GLDEF_C void gPanic( TMmsPanic aPanic ) // error number enumerations + { + _LIT(KMmsPanic,"MMS"); + User::Panic( KMmsPanic, aPanic ); + } + +// End of File