/*
* 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