--- /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 <txtrich.h>
+#include <msvids.h>
+#include <badesca.h>
+#include <msvstore.h>
+#include <mtmuids.h>
+#include <mtclbase.h>
+#include <mtmdef.h>
+#include <logcli.h>
+#include <msvftext.h> // CMsvFindText
+#include <cmsvmimeheaders.h>
+#include <mmsvattachmentmanager.h>
+#include <mmsvattachmentmanagersync.h>
+#include <charconv.h>
+#include <msgtextutils.h>
+
+// 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