diff -r 000000000000 -r 72b543305e3a mmsengine/mmspushhandler/src/CMmsPushHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmsengine/mmspushhandler/src/CMmsPushHandler.cpp Thu Dec 17 08:44:11 2009 +0200 @@ -0,0 +1,867 @@ +/* +* 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: ECOM plugin .dll for handling MMS related WAP push messages. +* +*/ + + + +// INCLUDE FILES +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mmsconst.h" +#include "mmscmds.h" +#include "CMmsPushHandler.h" +#include "mmsgenutils.h" + +// EXTERNAL DATA STRUCTURES + +// EXTERNAL FUNCTION PROTOTYPES + +// CONSTANTS +const TUint KMinimumNumberOfMessageFields = 6; +// ECOM framework related +const TImplementationProxy ImplementationTable[] = + { + // different definition for new compiler + IMPLEMENTATION_PROXY_ENTRY(0x101F4692, CMmsPushHandler::NewL) + }; + +// MACROS +// LOCAL CONSTANTS AND MACROS +// MODULE DATA STRUCTURES +// LOCAL FUNCTION PROTOTYPES +// FORWARD DECLARATIONS +// ============================= LOCAL FUNCTIONS =============================== +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::New +// 1st phase constructor +// Returns: : +// ----------------------------------------------------------------------------- +// +CMmsPushHandler* CMmsPushHandler::NewL() + { + CMmsPushHandler* self = new( ELeave ) CMmsPushHandler(); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + LOGTEXT(_L("***** CMmsPushHandler NewL() *****")); + return self; + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::CMmsPushHandler +// Initialises the object with zero/NULL values. +// ----------------------------------------------------------------------------- +// +CMmsPushHandler::CMmsPushHandler() + :CPushHandlerBase(), + iState( EInitial ), + iServiceId( KMsvNullIndexEntryId ), + iMsvSession( NULL ), + iMsvOperation( NULL ), + iPushMsg( NULL ), + iBody( NULL ), + iRetryCount( 0 ) + { + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::ConstructL +// +// ----------------------------------------------------------------------------- +// +void CMmsPushHandler::ConstructL() + { + // Connect to filesystem + User::LeaveIfError( iFs.Connect() ); + User::LeaveIfError( iTimer.CreateLocal() ); + + // Add plugin to AS + CActiveScheduler::Add( this ); + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::~CMmsPushHandler +// Destructor. Calls also baseclass destructor which calls +// REcomSession::DestroyedImplementation(iDtor_ID_Key) +// ----------------------------------------------------------------------------- +// +CMmsPushHandler::~CMmsPushHandler() + { + LOGTEXT(_L("~CMmsPushHandler()")); + + // AO's destructor always calls Cancel() + Cancel(); + + // Delete the necessary instance attributes + delete iMsvSession; + delete iMsvOperation; + delete iPushMsg; + delete iBody; + iFs.Close(); + iTimer.Close(); + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::HandleMessageL +// +// ----------------------------------------------------------------------------- +// +void CMmsPushHandler::HandleMessageL( + CPushMessage* aPushMsg, + TRequestStatus& aStatus ) + { + LOGTEXT(_L("Asynchronous HandleMessageL() called but not implemented.")); + + iPushMsg = aPushMsg; + SetConfirmationStatus( aStatus ); + SignalConfirmationStatus( KErrNotSupported ); + iPluginKiller->KillPushPlugin(); + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::HandleMessageL +// +// ----------------------------------------------------------------------------- +// +void CMmsPushHandler::HandleMessageL( CPushMessage* aPushMsg ) + { + LOGTEXT( _L("Synchronous HandleMessageL() called.") ); + + iPushMsg = aPushMsg; + + // + // Do sanity checks for the message. + // + TInt error = PerformChecks(); + if ( error ) + { + LOGTEXT2( _L("HandleMessageL(): PerformChecks failed with code %d, returning silently. Notification is lost."), error ); + + iPluginKiller->KillPushPlugin(); + return; + } + + // + // Store the messagebody into handler's attribute + // If memory runs out, tough luck.. + // + TPtrC8 messageBodyPtr; + iPushMsg->GetMessageBody( messageBodyPtr ); + iBody = messageBodyPtr.Alloc(); + if ( !iBody ) + { + LOGTEXT( _L("HandleMessageL(): Out of memory when allocating body buffer") ); + // Commit suicide - the caller expects it even if we leave + iPluginKiller->KillPushPlugin(); + User::Leave( KErrNoMemory ); + } + + // + // Setting 'this' active and complete in order to get to RunL + // + TRequestStatus* status = &iStatus; + iStatus = KRequestPending; + User::RequestComplete( status, KErrNone ); //iStatus = KErrNone + SetActive(); + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::CancelHandleMessage +// Cancels the pending asynchronous HandleMessageL. +// ----------------------------------------------------------------------------- +// +void CMmsPushHandler::CancelHandleMessage() + { + LOGTEXT( _L("CancelHandleMessage() called, but not supported.") ); + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::HandleSessionEventL +// +// ----------------------------------------------------------------------------- +// +void CMmsPushHandler::HandleSessionEventL( + TMsvSessionEvent aEvent, + TAny* /*aArg1*/, + TAny* /*aArg2*/, + TAny* /*aArg3*/) + { + switch (aEvent) + { + // If session is closed down, the object will be deleted + case EMsvCloseSession: + LOGTEXT(_L("HandleSessionEventL(): Session event EMsvCloseSession")); + // fall through on purpose + case EMsvServerTerminated: + LOGTEXT(_L("HandleSessionEventL(): Session event EMsvServerTerminated")); + if ( iMsvSession ) + { + delete iMsvSession; + iMsvSession = NULL; + } + break; + case EMsvMediaUnavailable: + LOGTEXT(_L("HandleSessionEventL(): EMsvMediaUnavailable")); + break; + default: + //Nothing + break; + } + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::DoCancel +// +// ----------------------------------------------------------------------------- +// +void CMmsPushHandler::DoCancel() + { + LOGTEXT( _L("DoCancel()") ); + if( iState == ETransferCommand && iMsvOperation ) + { + iMsvOperation->Cancel(); + } + else if( iState == EMsDriveChange && iMsvOperation ) + { + iMsvOperation->Cancel(); + } + else if( iState == ETimer ) + { + iTimer.Cancel(); + } + else if( iState == EDiskSpaceWait ) + { + iFs.NotifyDiskSpaceCancel(); + } + + // Finally clean up + iPluginKiller->KillPushPlugin(); + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::RunL +// Loops forever if MessageServer/ServerMtm respond correctly +// ----------------------------------------------------------------------------- +// +void CMmsPushHandler::RunL() + { + LOGTEXT(_L("RunL(): Starting")); + + // Check for cancel + if( iStatus == KErrCancel ) + { + LOGTEXT( _L("RunL(): Operation cancelled.") ); + iPluginKiller->KillPushPlugin(); + return; + } + + // Checking the retry count, because if something just keeps going wrong + // there is nothing that can be done + if( ++iRetryCount > KRetryCount ) + { + LOGTEXT( _L("RunL(): Retrycount exceeded, quitting. Notification is lost.") ); + iPluginKiller->KillPushPlugin(); + return; + } + + TInt error = KErrNone; + + // + // Operation: TransferCommand + // + if( iState == ETransferCommand ) + { + // Clean up + if( iMsvOperation ) + { + delete iMsvOperation; + iMsvOperation = NULL; + } + + // Go through statuses + if( iStatus == KErrNone ) + { + LOGTEXT( _L("RunL(): TransferCommandL() succeeded.") ); + iPluginKiller->KillPushPlugin(); + return; + } + else if( iStatus == KErrLocked ) // for a short wait + { + LOGTEXT2( _L("RunL(): TransferCommandL failed with code %d, entering short wait."), iStatus.Int() ); + iTimer.After( iStatus, KShortWait ); + iState = ETimer; + SetActive(); + return; + } + else // default is long wait + { + LOGTEXT2( _L("RunL(): TransferCommandL failed with code %d, entering long wait."), iStatus.Int() ); + iTimer.After( iStatus, KLongWait ); + iState = ETimer; + SetActive(); + return; + } + } + + // + // Open session if not open + // Session is needed to check drive + // + if ( !iMsvSession ) + { + TRAP( error, OpenSessionL() ); + if( error ) + { + LOGTEXT2( _L("RunL: OpenSessionL left with code %d, entering long wait."), error ); + iState = ETimer; + iTimer.After( iStatus, KLongWait ); + SetActive(); + return; + } + } + // + // Operation: MessageStore Drive Change + // + if( iState == EMsDriveChange ) + { + // Clean up + if( iMsvOperation ) + { + delete iMsvOperation; + iMsvOperation = NULL; + } + + // Drive should be now on 'C:' + // Asserting this: + if( iMsvSession->CurrentDriveL() != EDriveC ) + { + // if not, giving up without retrying + LOGTEXT( _L("RunL(): Drive change attempt did not work, returning silently. Notification is lost." ) ); + iPluginKiller->KillPushPlugin(); + return; + } + LOGTEXT( _L("RunL(): Drive change attempt succeeded." ) ); + } + + // + // Find MMS default serviceId if not yet found + // + if( iServiceId == 0 ) + { + TRAP( error, FindServiceL() ); + // If MessageStore is not available and push message is a notification, + // The message store must be moved to C: + // (delivery reports are handled on best effort basis) + if( ( error == KErrCorrupt || + error == KErrNotReady ) + && (*iBody)[1] == 0x82 ) + { + // Try changing MessageStore to C: + LOGTEXT2( _L("RunL: FindServiceL left with code %d, changing drive."), error ); + TRAP( error, { iMsvOperation = iMsvSession->ChangeDriveL( EDriveC, iStatus ); } ); + if( error == KErrNone ) + { + iState = EMsDriveChange; + SetActive(); + return; + } + else + { + LOGTEXT2( _L("RunL: ChangeDriveL left with code %d."), error ); + // This falls to the next if statement (below) on purpose + } + } + if( error != KErrNone ) // error is something else + { + LOGTEXT2( _L("RunL(): FindServiceL left with code %d, returning silently. Notification is lost."), error ); + iPluginKiller->KillPushPlugin(); + return; + } + if( iServiceId == 0 ) // if iService still is 0 (FindServiceL should have found this) + { + LOGTEXT( _L("RunL(): FindServiceL didn't find MMS serviceId, returning silently. Notification is lost." ) ); + iPluginKiller->KillPushPlugin(); + return; + } + } + + // + // Checking disk space before using it + // + TRAP( error, { error = CheckDiskSpaceL(); } ); + if( error == KErrDiskFull ) + { + // CheckDiskSpaceL has handled the situation, i.e. we should active already + return; + } + else if( error != KErrNone ) // other error + { + LOGTEXT2( _L("RunL(): CheckDiskSpaceL left with code %d, entering short wait."), error ); + iTimer.After( iStatus, KShortWait ); + iState = ETimer; + SetActive(); + return; + } + + // + // Transfer the push message to MessageServer side + // + TRAP( error, TransferMessageL() ); + if( error == KErrCorrupt // MMC is not present + && (*iBody)[1] == 0x82 ) // push message is a notification + { + LOGTEXT( _L("RunL: TransferMessageL left with code %d, changing drive.") ); + // Try changing MessageStore to C: + TRAP( error, { iMsvOperation = iMsvSession->ChangeDriveL( EDriveC, iStatus ); } ); + if( error == KErrNone ) + { + iState = EMsDriveChange; + SetActive(); + return; + } + else + { + LOGTEXT2( _L("RunL: ChangeDriveL left with code %d."), error ); + // This falls to the next if statement (below) on purpose + } + } + if( error != KErrNone ) // other error + { + LOGTEXT2( _L("RunL(): TransferMessageL left with code %d, entering short wait."), error ); + iTimer.After( iStatus, KShortWait ); + iState = ETimer; + SetActive(); + return; + } + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::CPushHandlerBase_Reserved1 +// +// ----------------------------------------------------------------------------- +// +void CMmsPushHandler::CPushHandlerBase_Reserved1() + { + User::Panic( + _L("CPushHandlerBase_Reserved1() not supported."), + KErrNotSupported ); + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::CPushHandlerBase_Reserved2 +// +// ----------------------------------------------------------------------------- +// +void CMmsPushHandler::CPushHandlerBase_Reserved2() + { + User::Panic( + _L("CPushHandlerBase_Reserved2() not supported."), + KErrNotSupported ); + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::PerformChecksL +// +// ----------------------------------------------------------------------------- +// +TInt CMmsPushHandler::PerformChecks() + { + // Check that message is not equal to NULL + if( !iPushMsg ) + { + LOGTEXT( _L("ERROR: Message == NULL.") ); + return KErrCorrupt; + } + + // Check that body is not equial to NULL + TPtrC8 messageBodyPtr; + TBool bodyPresent = EFalse; + bodyPresent = iPushMsg->GetMessageBody( messageBodyPtr ); + if( !bodyPresent ) + { + LOGTEXT( _L("ERROR: Message has NULL body.") ); + return KErrCorrupt; + } + + // KMinimumNumberOfMessageFields (6) is minimum number of message fields. + // This is a very "mild" check but + // at least it guarantees that there is no empty body in the message + if( messageBodyPtr.Size() < KMinimumNumberOfMessageFields ) + { + LOGTEXT( _L("ERROR: Message has too short body.") ); + return KErrCorrupt; + } + + // Check message-type + TPtrC contentTypePtr; + iPushMsg->GetContentType( contentTypePtr ); + _LIT( KMmsContentType, "application/vnd.wap.mms-message" ); + if( contentTypePtr.Compare( KMmsContentType ) != 0 ) + { + LOGTEXT2( _L("ERROR: ContentType == %S"), &contentTypePtr ); + return KErrCorrupt; + } + + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::OpenSessionL +// +// ----------------------------------------------------------------------------- +// +void CMmsPushHandler::OpenSessionL() + { + LOGTEXT( _L("OpenSessionL()") ); + iMsvSession = CMsvSession::OpenSyncL( *this ); + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::FindServiceL +// +// ----------------------------------------------------------------------------- +// +void CMmsPushHandler::FindServiceL() + { + LOGTEXT( _L("FindServiceL()") ); + + // Use first service found. There should never be more than one MMS Service + + // Create a new entry, showing invisible entries (because the service entry may be invisible) + TMsvSelectionOrdering ordering(KMsvNoGrouping, EMsvSortByNone, ETrue); + CMsvEntry* entry = CMsvEntry::NewL(*iMsvSession, KMsvRootIndexEntryId, ordering); + CleanupStack::PushL(entry); + + CMsvEntrySelection *sel=entry->ChildrenWithMtmL(KUidMsgTypeMultimedia); + CleanupStack::PushL(sel); + if(sel->Count() == 0) + { + User::Leave(KErrNotFound); + } + iServiceId=sel->At(0); + CleanupStack::PopAndDestroy( sel ); + CleanupStack::PopAndDestroy( entry ); + return; + + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::TransferMessageL +// +// ----------------------------------------------------------------------------- +// +void CMmsPushHandler::TransferMessageL() + { + LOGTEXT( _L("TransferMessageL()") ); + + // In order to get to mms service fast (not wait for our turn) + // we create an entry into our invisible mms directory. + // This entry will contain the binary notification + // and the service says "local service" with "MMS mtm" + + // + // Get entry id of the notifications folder + // + TMsvId mmsFolder = GetMMSFolderL(); + + // Create selection array + CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection; + CleanupStack::PushL( selection ); + + TMsvId tMsvId = CreateEntryL( mmsFolder ); + iMsvSession->CleanupEntryPushL( tMsvId ); + LOGTEXT2( _L("TransferMessageL(): Entry Created: %d"), tMsvId ); + + // + // The binary notification has been streamed into this entry. + // Now we have an entry that says: local service, MMS MTM + // + if ( tMsvId != KMsvNullIndexEntryId ) + { + LOGTEXT( _L("TransferMessageL(): iPushMessageId != KMsvNullIndexEntryId") ); + selection->AppendL( tMsvId ); + } + else + { + LOGTEXT( _L("TransferMessageL(): iPushMessageId == KMsvNullIndexEntryId") ); + selection->AppendL( iServiceId ); + } + LOGTEXT( _L("TransferMessageL(): iPushMessageId Appended to Selection.") ); + + // Watcher parameters have become obsolete as all data is transferred in the entry + TWatcherParameters parameters; + TWatcherParametersBuf paramPack( parameters ); + + // + // Make asynch call to transfer the push message + // + LOGTEXT( _L("TransferMessageL(): invoking asynchronous TransferCommandL()") ); + iMsvOperation = iMsvSession->TransferCommandL( + *selection, + EMmsDecodePushedMessage, + paramPack, + iStatus ); + iState = ETransferCommand; + SetActive(); + + iMsvSession->CleanupEntryPop(); // tMsvId + CleanupStack::PopAndDestroy( selection ); + LOGTEXT( _L("TransferMessageL() exiting") ); + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::CheckDiskSpaceL +// +// ----------------------------------------------------------------------------- +// +TInt CMmsPushHandler::CheckDiskSpaceL() + { + LOGTEXT( _L("CheckDiskSpaceL()") ); + TInt messageDrive = EDriveC; // C is default + messageDrive = iMsvSession->CurrentDriveL(); + LOGTEXT2( _L("CheckDiskSpaceL(): Current Drive = %d"), messageDrive ); + if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( + &iFs, + KRequiredDiskSpace, + messageDrive ) ) + { + LOGTEXT( _L("CheckDiskSpaceL(): Not Enough Diskspace, subscribing a notification from FileServer.") ); + TVolumeInfo volumeInfo; + User::LeaveIfError( iFs.Volume( volumeInfo, messageDrive ) ); + iFs.NotifyDiskSpace( + ( volumeInfo.iFree + KRequiredDiskSpace ), + messageDrive, + iStatus ); + iState = EDiskSpaceWait; + SetActive(); + return KErrDiskFull; + } + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::GetMMSFolderL +// Creates an MMS folder into MessageServer's message store. +// (As a subfolder of LocalService.) +// Returns: : Entry Id of the created MMS folder. +// ----------------------------------------------------------------------------- +// +TMsvId CMmsPushHandler::GetMMSFolderL() + { + LOGTEXT( _L("GetMMSFolderL()") ); + + // First check if proper MMS folder already exists + TMsvId mmsFolderId = FindMMSFolderL(); + + // If below is true, the folder did not exist already and has to be created. + // This should not happen unless the message store is corrupted + if ( mmsFolderId == KMsvNullIndexEntryId ) + { + mmsFolderId = CreateMMSFolderL(); + } + + return mmsFolderId; + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::CreateMMSFolderL +// Creates MMSNotifications folder into Message Store. +// (As a subfolder of LocalService.) +// Returns: : Entry Id of the created MMS folder. +// ----------------------------------------------------------------------------- +// +TMsvId CMmsPushHandler::CreateMMSFolderL() + { + LOGTEXT( _L("CreateMMSFolderL()") ); + // + // Create entry + // + TMsvEntry entry; + entry.iType = KUidMsvFolderEntry; + entry.iMtm = KUidMsvLocalServiceMtm; + entry.iDetails.Set( KMMSNotificationFolder ); + entry.SetVisible( EFalse ); + entry.SetInPreparation( EFalse ); + entry.iServiceId = KMsvLocalServiceIndexEntryId; + + // + // Make the created entry to be a subfolder of LocalService + // + CMsvEntry* cMsvEntry + = iMsvSession->GetEntryL( KMsvLocalServiceIndexEntryId ); + CleanupStack::PushL( cMsvEntry ); + cMsvEntry->CreateL( entry ); + CleanupStack::PopAndDestroy( cMsvEntry ); + + return entry.Id(); + } + + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::FindMMSFolderL +// Checks if MMS folder entry already exists. +// Returns: KMMSNotificationFolder: Entry Id of the found MMS folder +// KMsvNullIndexEntryId: MMS folder was not found +// ----------------------------------------------------------------------------- +// +TMsvId CMmsPushHandler::FindMMSFolderL() + { + LOGTEXT( _L("FindMMSFolderL()") ); + + TMsvId mmsFolderId = KMsvNullIndexEntryId; + + // Get Local Service as parent entry + CMsvEntry* cMsvEntry = iMsvSession->GetEntryL( KMsvLocalServiceIndexEntryId ); + CleanupStack::PushL( cMsvEntry ); + // show invisible entries + cMsvEntry->SetSortTypeL( TMsvSelectionOrdering( KMsvNoGrouping, + EMsvSortByIdReverse, + ETrue ) ); + // Get all folder entries. + CMsvEntrySelection* selection + = cMsvEntry->ChildrenWithTypeL( KUidMsvFolderEntry ); + CleanupStack::PushL( selection ); + + // Now we should have a list of all local folders. + // Prune away the standard folders. + // They should be at the end of the list + TInt count = selection->Count(); + TInt i; + for ( i = count - 1; i >= 0; i-- ) + { + if ( selection->At( i ) <= KMsvDeletedEntryFolderEntryId ) + { + // Anything below this should not be ours + selection->Delete( i ); + } + } + + // Check if anything left. + count = selection->Count(); + // Loop through the rest and find possible correct folder + for ( i = 0; i < count && mmsFolderId == KMsvNullIndexEntryId; i++ ) + { + cMsvEntry->SetEntryL( selection->At( i ) ); + // must be exact match + if (cMsvEntry->Entry().iDetails.Compare( KMMSNotificationFolder ) == 0) + { + mmsFolderId = selection->At( i ); + } + } + CleanupStack::PopAndDestroy( selection ); + CleanupStack::PopAndDestroy( cMsvEntry ); + + // If folder does not exist -> returns KMsvNullIndexEntryId + // If folder exists -> returns its Id + return mmsFolderId; + } + +// ----------------------------------------------------------------------------- +// CMmsPushHandler::CreateEntryL +// +// ----------------------------------------------------------------------------- +// +TMsvId CMmsPushHandler::CreateEntryL( TMsvId aFolder ) + { + LOGTEXT( _L("CreateEntryL()") ); + // + // Basic "NULL test" + // + if( aFolder == KMsvNullIndexEntryId ) + { + // No folder, no entry + return KMsvNullIndexEntryId; + } + + // + // Get CMsvEntry context of the target folder + // + CMsvEntry* cMsvEntry = iMsvSession->GetEntryL( aFolder ); + CleanupStack::PushL( cMsvEntry ); // *** + + // + // Create an entry representing the notification + // + TMsvEntry tMsvEntry; + tMsvEntry.iType = KUidMsvMessageEntry; + tMsvEntry.iMtm = KUidMsgTypeMultimedia; + tMsvEntry.iServiceId = KMsvLocalServiceIndexEntryId; + tMsvEntry.iRelatedId = iServiceId; + tMsvEntry.iMtmData2 = KMmsNotificationBinary; + // Visible and inPreparation flags will be changed after data has been + // successfully streamed + tMsvEntry.SetVisible( EFalse ); + tMsvEntry.SetInPreparation( ETrue ); + cMsvEntry->CreateL( tMsvEntry ); + + // + // Stream + // 1) length of the data as 32 bit integer + // 2) pushed message data + // into created entry's stream + // + cMsvEntry->SetEntryL( tMsvEntry.Id() ); + CMsvStore* store = cMsvEntry->EditStoreL(); + CleanupStack::PushL( store ); // *** + RMsvWriteStream outs; + outs.AssignLC( *store, KUidBinaryNotificationStream ); // *** + outs.WriteUint32L( iBody->Size() ); + LOGTEXT2( _L(" - streamed %d bytes into dummy-entry's store"), iBody->Size() ); + outs.WriteL( *iBody ); + outs.CommitL(); + outs.Close(); + store->CommitL(); + CleanupStack::PopAndDestroy( &outs ); //outs + CleanupStack::PopAndDestroy( store ); + // + // Now, change the flags to their final values + // + tMsvEntry.SetVisible( ETrue ); + tMsvEntry.SetInPreparation( EFalse ); + cMsvEntry->ChangeL( tMsvEntry ); + CleanupStack::PopAndDestroy( cMsvEntry ); + + return tMsvEntry.Id(); + } + +// ========================== OTHER EXPORTED FUNCTIONS ========================= + +// ----------------------------------------------------------------------------- +// ImplementationGroupProxy +// Returns: TImplementationProxy*: Implementation table to the ECOM framework +// ----------------------------------------------------------------------------- +// +EXPORT_C const TImplementationProxy* ImplementationGroupProxy( TInt& aTableCount ) + { + aTableCount = sizeof( ImplementationTable ) / sizeof( TImplementationProxy ); + + return ImplementationTable; + } + +// End of File