--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmsengine/mmspushhandler/src/CMmsPushHandler.cpp Fri Jun 04 10:25:39 2010 +0100
@@ -0,0 +1,869 @@
+/*
+* 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 <e32std.h>
+#include <msvapi.h>
+#include <msvids.h>
+#include <msvuids.h>
+#include <e32math.h>
+#include <apparc.h>
+
+#include <push/cpushhandlerbase.h>
+#include <ecom/implementationproxy.h>
+#include <push/pluginkiller.h>
+#include <push/pushmessage.h>
+#include <push/pushlog.h>
+
+#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: <new CMmsPushHandler>:
+// -----------------------------------------------------------------------------
+//
+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;
+ if ( 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: <new TMsvId>: 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: <new TMsvId>: 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