mmsengine/mmspushhandler/src/CMmsPushHandler.cpp
changeset 0 72b543305e3a
child 1 d09ac5c1e252
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 /*
       
     2 * Copyright (c) 2002-2007 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:   ECOM plugin .dll for handling MMS related WAP push messages.
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 // INCLUDE FILES
       
    21 #include <e32std.h>
       
    22 #include <msvapi.h>
       
    23 #include <msvids.h>
       
    24 #include <msvuids.h>
       
    25 #include <e32math.h>
       
    26 #include <apparc.h>
       
    27 
       
    28 #include <cpushhandlerbase.h>
       
    29 #include <implementationproxy.h>
       
    30 #include <pluginkiller.h>
       
    31 #include <pushmessage.h>
       
    32 #include <pushlog.h>
       
    33 
       
    34 #include "mmsconst.h"
       
    35 #include "mmscmds.h"
       
    36 #include "CMmsPushHandler.h"
       
    37 #include "mmsgenutils.h"
       
    38 
       
    39 // EXTERNAL DATA STRUCTURES
       
    40 
       
    41 // EXTERNAL FUNCTION PROTOTYPES  
       
    42 
       
    43 // CONSTANTS
       
    44 const TUint KMinimumNumberOfMessageFields = 6;
       
    45 // ECOM framework related
       
    46 const TImplementationProxy ImplementationTable[] = 
       
    47     {
       
    48     // different definition for new compiler
       
    49     IMPLEMENTATION_PROXY_ENTRY(0x101F4692, CMmsPushHandler::NewL)
       
    50     };
       
    51 
       
    52 // MACROS
       
    53 // LOCAL CONSTANTS AND MACROS
       
    54 // MODULE DATA STRUCTURES
       
    55 // LOCAL FUNCTION PROTOTYPES
       
    56 // FORWARD DECLARATIONS
       
    57 // ============================= LOCAL FUNCTIONS ===============================
       
    58 // ============================ MEMBER FUNCTIONS ===============================
       
    59 
       
    60 // -----------------------------------------------------------------------------
       
    61 // CMmsPushHandler::New
       
    62 // 1st phase constructor
       
    63 // Returns: <new CMmsPushHandler>:
       
    64 // -----------------------------------------------------------------------------
       
    65 //
       
    66 CMmsPushHandler* CMmsPushHandler::NewL()
       
    67     {
       
    68     CMmsPushHandler* self = new( ELeave ) CMmsPushHandler();
       
    69     CleanupStack::PushL( self );
       
    70     self->ConstructL();
       
    71     CleanupStack::Pop( self );
       
    72     LOGTEXT(_L("***** CMmsPushHandler NewL() *****"));
       
    73     return self;
       
    74     }
       
    75 
       
    76 // -----------------------------------------------------------------------------
       
    77 // CMmsPushHandler::CMmsPushHandler
       
    78 // Initialises the object with zero/NULL values.
       
    79 // -----------------------------------------------------------------------------
       
    80 //
       
    81 CMmsPushHandler::CMmsPushHandler()
       
    82     :CPushHandlerBase(),
       
    83     iState( EInitial ),
       
    84     iServiceId( KMsvNullIndexEntryId ),
       
    85     iMsvSession( NULL ),
       
    86     iMsvOperation( NULL ),
       
    87     iPushMsg( NULL ),
       
    88     iBody( NULL ),
       
    89     iRetryCount( 0 )
       
    90     {
       
    91     }
       
    92 
       
    93 // -----------------------------------------------------------------------------
       
    94 // CMmsPushHandler::ConstructL
       
    95 //
       
    96 // -----------------------------------------------------------------------------
       
    97 //
       
    98 void CMmsPushHandler::ConstructL()
       
    99     {
       
   100     // Connect to filesystem
       
   101     User::LeaveIfError( iFs.Connect() );
       
   102     User::LeaveIfError( iTimer.CreateLocal() );
       
   103 
       
   104     // Add plugin to AS
       
   105     CActiveScheduler::Add( this );
       
   106     }
       
   107 
       
   108 // -----------------------------------------------------------------------------
       
   109 // CMmsPushHandler::~CMmsPushHandler
       
   110 // Destructor. Calls also baseclass destructor which calls
       
   111 //  REcomSession::DestroyedImplementation(iDtor_ID_Key)
       
   112 // -----------------------------------------------------------------------------
       
   113 //
       
   114 CMmsPushHandler::~CMmsPushHandler()
       
   115     {
       
   116     LOGTEXT(_L("~CMmsPushHandler()"));
       
   117 
       
   118     // AO's destructor always calls Cancel()
       
   119     Cancel();
       
   120 
       
   121     // Delete the necessary instance attributes
       
   122     delete iMsvSession;
       
   123     delete iMsvOperation;
       
   124     delete iPushMsg;
       
   125     delete iBody;
       
   126     iFs.Close();
       
   127     iTimer.Close();
       
   128     }
       
   129 
       
   130 // -----------------------------------------------------------------------------
       
   131 // CMmsPushHandler::HandleMessageL
       
   132 // 
       
   133 // -----------------------------------------------------------------------------
       
   134 //
       
   135 void CMmsPushHandler::HandleMessageL(
       
   136     CPushMessage* aPushMsg,
       
   137     TRequestStatus& aStatus )
       
   138     {
       
   139     LOGTEXT(_L("Asynchronous HandleMessageL() called but not implemented."));
       
   140 
       
   141     iPushMsg = aPushMsg;
       
   142     SetConfirmationStatus( aStatus );
       
   143     SignalConfirmationStatus( KErrNotSupported );
       
   144     iPluginKiller->KillPushPlugin();
       
   145     }
       
   146 
       
   147 // -----------------------------------------------------------------------------
       
   148 // CMmsPushHandler::HandleMessageL
       
   149 // 
       
   150 // -----------------------------------------------------------------------------
       
   151 //
       
   152 void CMmsPushHandler::HandleMessageL( CPushMessage* aPushMsg )
       
   153     {
       
   154     LOGTEXT( _L("Synchronous HandleMessageL() called.") );
       
   155 
       
   156     iPushMsg = aPushMsg;
       
   157 
       
   158     //
       
   159     // Do sanity checks for the message.
       
   160     //
       
   161     TInt error = PerformChecks();
       
   162     if ( error )
       
   163         {
       
   164         LOGTEXT2( _L("HandleMessageL(): PerformChecks failed with code %d, returning silently. Notification is lost."), error );
       
   165         
       
   166         iPluginKiller->KillPushPlugin();        
       
   167         return;
       
   168         }
       
   169 
       
   170     //
       
   171     // Store the messagebody into handler's attribute
       
   172     // If memory runs out, tough luck..
       
   173     //
       
   174     TPtrC8 messageBodyPtr;
       
   175     iPushMsg->GetMessageBody( messageBodyPtr );
       
   176     iBody = messageBodyPtr.Alloc();
       
   177     if ( !iBody )
       
   178         {
       
   179         LOGTEXT( _L("HandleMessageL(): Out of memory when allocating body buffer") );
       
   180         // Commit suicide - the caller expects it even if we leave
       
   181         iPluginKiller->KillPushPlugin();
       
   182         User::Leave( KErrNoMemory );
       
   183         }
       
   184     
       
   185     //
       
   186     // Setting 'this' active and complete in order to get to RunL
       
   187     //
       
   188     TRequestStatus* status = &iStatus;
       
   189     iStatus = KRequestPending;
       
   190     User::RequestComplete( status, KErrNone ); //iStatus = KErrNone
       
   191     SetActive();
       
   192     }
       
   193 
       
   194 // -----------------------------------------------------------------------------
       
   195 // CMmsPushHandler::CancelHandleMessage
       
   196 // Cancels the pending asynchronous HandleMessageL.
       
   197 // -----------------------------------------------------------------------------
       
   198 //
       
   199 void CMmsPushHandler::CancelHandleMessage()
       
   200     {
       
   201     LOGTEXT( _L("CancelHandleMessage() called, but not supported.") );
       
   202     }
       
   203 
       
   204 // -----------------------------------------------------------------------------
       
   205 // CMmsPushHandler::HandleSessionEventL
       
   206 // 
       
   207 // -----------------------------------------------------------------------------
       
   208 //
       
   209 void CMmsPushHandler::HandleSessionEventL(
       
   210     TMsvSessionEvent aEvent, 
       
   211     TAny* /*aArg1*/, 
       
   212     TAny* /*aArg2*/, 
       
   213     TAny* /*aArg3*/)
       
   214     {
       
   215     switch (aEvent)
       
   216         {
       
   217         // If session is closed down, the object will be deleted
       
   218         case EMsvCloseSession:
       
   219             LOGTEXT(_L("HandleSessionEventL(): Session event EMsvCloseSession"));
       
   220             // fall through on purpose
       
   221         case EMsvServerTerminated:
       
   222             LOGTEXT(_L("HandleSessionEventL(): Session event EMsvServerTerminated"));
       
   223             if ( iMsvSession )
       
   224                 {
       
   225                 delete iMsvSession;
       
   226                 iMsvSession = NULL;
       
   227                 }
       
   228             break;
       
   229         case EMsvMediaUnavailable:
       
   230             LOGTEXT(_L("HandleSessionEventL(): EMsvMediaUnavailable"));
       
   231             break;
       
   232         default:
       
   233             //Nothing
       
   234             break;
       
   235         }
       
   236     }
       
   237 
       
   238 // -----------------------------------------------------------------------------
       
   239 // CMmsPushHandler::DoCancel
       
   240 // 
       
   241 // -----------------------------------------------------------------------------
       
   242 //
       
   243 void CMmsPushHandler::DoCancel()
       
   244     {
       
   245     LOGTEXT( _L("DoCancel()") );
       
   246     if( iState == ETransferCommand && iMsvOperation )
       
   247         {
       
   248         iMsvOperation->Cancel();
       
   249         }
       
   250     else if( iState == EMsDriveChange && iMsvOperation )
       
   251         {
       
   252         iMsvOperation->Cancel();
       
   253         }
       
   254     else if( iState == ETimer )
       
   255         {
       
   256         iTimer.Cancel();
       
   257         }
       
   258     else if( iState == EDiskSpaceWait )
       
   259         {
       
   260         iFs.NotifyDiskSpaceCancel();
       
   261         }
       
   262 
       
   263     // Finally clean up
       
   264     iPluginKiller->KillPushPlugin();
       
   265     }
       
   266 
       
   267 // -----------------------------------------------------------------------------
       
   268 // CMmsPushHandler::RunL
       
   269 // Loops forever if MessageServer/ServerMtm respond correctly
       
   270 // -----------------------------------------------------------------------------
       
   271 //
       
   272 void CMmsPushHandler::RunL()
       
   273     {
       
   274     LOGTEXT(_L("RunL(): Starting"));
       
   275 
       
   276     // Check for cancel
       
   277     if( iStatus == KErrCancel )
       
   278         {
       
   279         LOGTEXT( _L("RunL(): Operation cancelled.") );
       
   280         iPluginKiller->KillPushPlugin();
       
   281         return;
       
   282         }
       
   283 
       
   284     // Checking the retry count, because if something just keeps going wrong
       
   285     // there is nothing that can be done
       
   286     if( ++iRetryCount > KRetryCount )
       
   287         {
       
   288         LOGTEXT( _L("RunL(): Retrycount exceeded, quitting. Notification is lost.") );
       
   289         iPluginKiller->KillPushPlugin();
       
   290         return;
       
   291         }
       
   292 
       
   293     TInt error = KErrNone;
       
   294 
       
   295     //
       
   296     // Operation: TransferCommand
       
   297     //
       
   298     if( iState == ETransferCommand )
       
   299         {
       
   300         // Clean up
       
   301         if( iMsvOperation )
       
   302             {
       
   303             delete iMsvOperation;
       
   304             iMsvOperation = NULL;
       
   305             }
       
   306 
       
   307         // Go through statuses
       
   308         if( iStatus == KErrNone )
       
   309             {
       
   310             LOGTEXT( _L("RunL(): TransferCommandL() succeeded.") );
       
   311             iPluginKiller->KillPushPlugin();
       
   312             return;
       
   313             }
       
   314         else if( iStatus == KErrLocked ) // for a short wait
       
   315             {
       
   316             LOGTEXT2( _L("RunL(): TransferCommandL failed with code %d, entering short wait."), iStatus.Int() );
       
   317             iTimer.After( iStatus, KShortWait );
       
   318             iState = ETimer;
       
   319             SetActive();
       
   320             return;
       
   321             }
       
   322         else // default is long wait
       
   323             {
       
   324             LOGTEXT2( _L("RunL(): TransferCommandL failed with code %d, entering long wait."), iStatus.Int() );
       
   325             iTimer.After( iStatus, KLongWait );
       
   326             iState = ETimer;
       
   327             SetActive();
       
   328             return;
       
   329             }
       
   330         }
       
   331 
       
   332     //
       
   333     // Open session if not open
       
   334     // Session is needed to check drive
       
   335     //
       
   336     if ( !iMsvSession  )
       
   337         {
       
   338         TRAP( error, OpenSessionL() );
       
   339         if( error )
       
   340             {
       
   341             LOGTEXT2( _L("RunL: OpenSessionL left with code %d, entering long wait."), error );
       
   342             iState = ETimer;
       
   343             iTimer.After( iStatus, KLongWait );
       
   344             SetActive();
       
   345             return;
       
   346             }
       
   347         }
       
   348     //
       
   349     // Operation: MessageStore Drive Change
       
   350     //
       
   351     if( iState == EMsDriveChange )
       
   352         {
       
   353         // Clean up
       
   354         if( iMsvOperation )
       
   355             {
       
   356             delete iMsvOperation;
       
   357             iMsvOperation = NULL;
       
   358             }
       
   359 
       
   360         // Drive should be now on 'C:'
       
   361         // Asserting this:
       
   362         if( iMsvSession->CurrentDriveL() != EDriveC )
       
   363             {
       
   364             // if not, giving up without retrying
       
   365             LOGTEXT( _L("RunL(): Drive change attempt did not work, returning silently. Notification is lost." ) );
       
   366             iPluginKiller->KillPushPlugin();
       
   367             return;                        
       
   368             }
       
   369         LOGTEXT( _L("RunL(): Drive change attempt succeeded." ) );        
       
   370         }
       
   371 
       
   372     //
       
   373     // Find MMS default serviceId if not yet found
       
   374     //
       
   375     if( iServiceId == 0 )
       
   376         {
       
   377         TRAP( error, FindServiceL() );
       
   378         // If MessageStore is not available and push message is a notification,
       
   379         // The message store must be moved to C:
       
   380         // (delivery reports are handled on best effort basis)
       
   381         if( ( error == KErrCorrupt ||         
       
   382               error == KErrNotReady )          
       
   383             && (*iBody)[1] == 0x82 )
       
   384             { 
       
   385             // Try changing MessageStore to C:
       
   386             LOGTEXT2( _L("RunL: FindServiceL left with code %d, changing drive."), error );
       
   387             TRAP( error, { iMsvOperation = iMsvSession->ChangeDriveL( EDriveC, iStatus ); } );
       
   388             if( error == KErrNone )
       
   389                 {
       
   390                 iState = EMsDriveChange;
       
   391                 SetActive();
       
   392                 return;
       
   393                 }
       
   394             else
       
   395                 {
       
   396                 LOGTEXT2( _L("RunL: ChangeDriveL left with code %d."), error );
       
   397                 // This falls to the next if statement (below) on purpose
       
   398                 }
       
   399             }
       
   400         if( error != KErrNone ) // error is something else
       
   401             {
       
   402             LOGTEXT2( _L("RunL(): FindServiceL left with code %d, returning silently. Notification is lost."), error );
       
   403             iPluginKiller->KillPushPlugin();
       
   404             return;            
       
   405             }
       
   406         if( iServiceId == 0 ) // if iService still is 0 (FindServiceL should have found this)
       
   407             {
       
   408             LOGTEXT( _L("RunL(): FindServiceL didn't find MMS serviceId, returning silently. Notification is lost." ) );        
       
   409             iPluginKiller->KillPushPlugin();
       
   410             return;            
       
   411             }
       
   412         }
       
   413 
       
   414     //
       
   415     // Checking disk space before using it
       
   416     //
       
   417     TRAP( error, { error = CheckDiskSpaceL(); } );
       
   418     if( error == KErrDiskFull )
       
   419         {
       
   420         // CheckDiskSpaceL has handled the situation, i.e. we should active already
       
   421         return;
       
   422         }
       
   423     else if( error != KErrNone ) // other error
       
   424         {
       
   425         LOGTEXT2( _L("RunL(): CheckDiskSpaceL left with code %d, entering short wait."), error );
       
   426         iTimer.After( iStatus, KShortWait );
       
   427         iState = ETimer;
       
   428         SetActive();
       
   429         return;
       
   430         }
       
   431 
       
   432     //
       
   433     // Transfer the push message to MessageServer side
       
   434     //
       
   435     TRAP( error, TransferMessageL() );
       
   436     if( error == KErrCorrupt     // MMC is not present
       
   437         && (*iBody)[1] == 0x82 ) // push message is a notification
       
   438         {
       
   439         LOGTEXT( _L("RunL: TransferMessageL left with code %d, changing drive.") );
       
   440         // Try changing MessageStore to C:
       
   441         TRAP( error, { iMsvOperation = iMsvSession->ChangeDriveL( EDriveC, iStatus ); } );
       
   442         if( error == KErrNone )
       
   443             {
       
   444             iState = EMsDriveChange;
       
   445             SetActive();
       
   446             return;
       
   447             }
       
   448         else
       
   449             {
       
   450             LOGTEXT2( _L("RunL: ChangeDriveL left with code %d."), error );
       
   451             // This falls to the next if statement (below) on purpose
       
   452             }
       
   453         }
       
   454     if( error != KErrNone ) // other error
       
   455         {
       
   456         LOGTEXT2( _L("RunL(): TransferMessageL left with code %d, entering short wait."), error );
       
   457         iTimer.After( iStatus, KShortWait );
       
   458         iState = ETimer;
       
   459         SetActive();
       
   460         return;
       
   461         }
       
   462     }
       
   463 
       
   464 // -----------------------------------------------------------------------------
       
   465 // CMmsPushHandler::CPushHandlerBase_Reserved1
       
   466 // 
       
   467 // -----------------------------------------------------------------------------
       
   468 //
       
   469 void CMmsPushHandler::CPushHandlerBase_Reserved1()
       
   470     {
       
   471     User::Panic(
       
   472         _L("CPushHandlerBase_Reserved1() not supported."), 
       
   473         KErrNotSupported );
       
   474     }
       
   475 
       
   476 // -----------------------------------------------------------------------------
       
   477 // CMmsPushHandler::CPushHandlerBase_Reserved2
       
   478 // 
       
   479 // -----------------------------------------------------------------------------
       
   480 //
       
   481 void CMmsPushHandler::CPushHandlerBase_Reserved2()
       
   482     {
       
   483     User::Panic(
       
   484         _L("CPushHandlerBase_Reserved2() not supported."),
       
   485         KErrNotSupported );
       
   486     }
       
   487 
       
   488 // -----------------------------------------------------------------------------
       
   489 // CMmsPushHandler::PerformChecksL
       
   490 // 
       
   491 // -----------------------------------------------------------------------------
       
   492 //
       
   493 TInt CMmsPushHandler::PerformChecks()
       
   494     {
       
   495     // Check that message is not equal to NULL
       
   496     if( !iPushMsg )
       
   497         {
       
   498         LOGTEXT( _L("ERROR: Message == NULL.") );
       
   499         return KErrCorrupt;
       
   500         }
       
   501 
       
   502     // Check that body is not equial to NULL
       
   503     TPtrC8 messageBodyPtr;
       
   504     TBool bodyPresent = EFalse;
       
   505     bodyPresent = iPushMsg->GetMessageBody( messageBodyPtr );
       
   506     if( !bodyPresent )
       
   507         {
       
   508         LOGTEXT( _L("ERROR: Message has NULL body.") );
       
   509         return KErrCorrupt;
       
   510         }
       
   511 
       
   512     // KMinimumNumberOfMessageFields (6) is minimum number of message fields. 
       
   513     // This is a very "mild" check but
       
   514     // at least it guarantees that there is no empty body in the message
       
   515     if( messageBodyPtr.Size() < KMinimumNumberOfMessageFields )
       
   516         {
       
   517         LOGTEXT( _L("ERROR: Message has too short body.") );
       
   518         return KErrCorrupt;
       
   519         }
       
   520 
       
   521     // Check message-type
       
   522     TPtrC contentTypePtr;
       
   523     iPushMsg->GetContentType( contentTypePtr );
       
   524     _LIT( KMmsContentType, "application/vnd.wap.mms-message" );
       
   525     if( contentTypePtr.Compare( KMmsContentType ) != 0 )
       
   526         {
       
   527         LOGTEXT2( _L("ERROR: ContentType == %S"), &contentTypePtr );
       
   528         return KErrCorrupt;
       
   529         }
       
   530 
       
   531     return KErrNone;
       
   532     }
       
   533 
       
   534 // -----------------------------------------------------------------------------
       
   535 // CMmsPushHandler::OpenSessionL
       
   536 // 
       
   537 // -----------------------------------------------------------------------------
       
   538 //
       
   539 void CMmsPushHandler::OpenSessionL()
       
   540     {
       
   541     LOGTEXT( _L("OpenSessionL()") );
       
   542     iMsvSession = CMsvSession::OpenSyncL( *this );
       
   543     }
       
   544 
       
   545 // -----------------------------------------------------------------------------
       
   546 // CMmsPushHandler::FindServiceL
       
   547 // 
       
   548 // -----------------------------------------------------------------------------
       
   549 //
       
   550 void CMmsPushHandler::FindServiceL()
       
   551     {
       
   552     LOGTEXT( _L("FindServiceL()") );
       
   553     
       
   554     // Use first service found. There should never be more than one MMS Service
       
   555     
       
   556     // Create a new entry, showing invisible entries (because the service entry may be invisible)
       
   557     TMsvSelectionOrdering ordering(KMsvNoGrouping, EMsvSortByNone, ETrue);
       
   558     CMsvEntry* entry = CMsvEntry::NewL(*iMsvSession, KMsvRootIndexEntryId, ordering);
       
   559     CleanupStack::PushL(entry);
       
   560 	
       
   561  	CMsvEntrySelection *sel=entry->ChildrenWithMtmL(KUidMsgTypeMultimedia);
       
   562 	CleanupStack::PushL(sel);
       
   563 	if(sel->Count() == 0)
       
   564 	    {
       
   565 	    User::Leave(KErrNotFound);
       
   566 	    } 
       
   567 	iServiceId=sel->At(0);
       
   568  	CleanupStack::PopAndDestroy( sel );
       
   569  	CleanupStack::PopAndDestroy( entry );
       
   570  	return;
       
   571     
       
   572     }
       
   573 
       
   574 // -----------------------------------------------------------------------------
       
   575 // CMmsPushHandler::TransferMessageL
       
   576 // 
       
   577 // -----------------------------------------------------------------------------
       
   578 //
       
   579 void CMmsPushHandler::TransferMessageL()
       
   580     {
       
   581     LOGTEXT( _L("TransferMessageL()") );
       
   582 
       
   583     // In order to get to mms service fast (not wait for our turn)
       
   584     // we create an entry into our invisible mms directory.
       
   585     // This entry will contain the binary notification
       
   586     // and the service says "local service" with "MMS mtm"
       
   587 
       
   588     //
       
   589     // Get entry id of the notifications folder
       
   590     //
       
   591     TMsvId mmsFolder = GetMMSFolderL();
       
   592 
       
   593     // Create selection array
       
   594     CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
       
   595     CleanupStack::PushL( selection );
       
   596 
       
   597     TMsvId tMsvId = CreateEntryL( mmsFolder );
       
   598     iMsvSession->CleanupEntryPushL( tMsvId );
       
   599     LOGTEXT2( _L("TransferMessageL(): Entry Created: %d"), tMsvId );
       
   600 
       
   601     //
       
   602     // The binary notification has been streamed into this entry.
       
   603     // Now we have an entry that says: local service, MMS MTM
       
   604     //
       
   605     if ( tMsvId != KMsvNullIndexEntryId )
       
   606         {
       
   607         LOGTEXT( _L("TransferMessageL(): iPushMessageId != KMsvNullIndexEntryId") );
       
   608         selection->AppendL( tMsvId );
       
   609         }
       
   610     else
       
   611         {
       
   612         LOGTEXT( _L("TransferMessageL(): iPushMessageId == KMsvNullIndexEntryId") );
       
   613         selection->AppendL( iServiceId );
       
   614         }
       
   615     LOGTEXT( _L("TransferMessageL(): iPushMessageId Appended to Selection.") );
       
   616 
       
   617     // Watcher parameters have become obsolete as all data is transferred in the entry
       
   618     TWatcherParameters parameters;
       
   619     TWatcherParametersBuf paramPack( parameters );
       
   620 
       
   621     //
       
   622     // Make asynch call to transfer the push message
       
   623     //
       
   624     LOGTEXT( _L("TransferMessageL(): invoking asynchronous TransferCommandL()") );
       
   625     iMsvOperation = iMsvSession->TransferCommandL(
       
   626         *selection,
       
   627         EMmsDecodePushedMessage, 
       
   628         paramPack, 
       
   629         iStatus );
       
   630     iState = ETransferCommand;
       
   631     SetActive();
       
   632 
       
   633     iMsvSession->CleanupEntryPop(); // tMsvId
       
   634     CleanupStack::PopAndDestroy( selection );
       
   635     LOGTEXT( _L("TransferMessageL() exiting") );
       
   636     }
       
   637 
       
   638 // -----------------------------------------------------------------------------
       
   639 // CMmsPushHandler::CheckDiskSpaceL
       
   640 //
       
   641 // -----------------------------------------------------------------------------
       
   642 //
       
   643 TInt CMmsPushHandler::CheckDiskSpaceL()
       
   644     {
       
   645     LOGTEXT( _L("CheckDiskSpaceL()") );
       
   646     TInt messageDrive = EDriveC; // C is default
       
   647     messageDrive = iMsvSession->CurrentDriveL();
       
   648     LOGTEXT2( _L("CheckDiskSpaceL(): Current Drive = %d"), messageDrive );
       
   649     if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( 
       
   650         &iFs, 
       
   651         KRequiredDiskSpace, 
       
   652         messageDrive ) )
       
   653         {
       
   654         LOGTEXT( _L("CheckDiskSpaceL(): Not Enough Diskspace, subscribing a notification from FileServer.") );
       
   655         TVolumeInfo volumeInfo;
       
   656         User::LeaveIfError( iFs.Volume( volumeInfo, messageDrive ) );
       
   657         iFs.NotifyDiskSpace( 
       
   658             ( volumeInfo.iFree + KRequiredDiskSpace ), 
       
   659             messageDrive, 
       
   660             iStatus );
       
   661         iState = EDiskSpaceWait;
       
   662         SetActive();
       
   663         return KErrDiskFull;
       
   664         }
       
   665     return KErrNone;
       
   666     }
       
   667 
       
   668 // -----------------------------------------------------------------------------
       
   669 // CMmsPushHandler::GetMMSFolderL
       
   670 // Creates an MMS folder into MessageServer's message store.
       
   671 // (As a subfolder of LocalService.)
       
   672 // Returns: <new TMsvId>: Entry Id of the created MMS folder.
       
   673 // -----------------------------------------------------------------------------
       
   674 //
       
   675 TMsvId CMmsPushHandler::GetMMSFolderL()
       
   676     {
       
   677     LOGTEXT( _L("GetMMSFolderL()") );
       
   678 
       
   679     // First check if proper MMS folder already exists
       
   680     TMsvId mmsFolderId = FindMMSFolderL();
       
   681 
       
   682     // If below is true, the folder did not exist already and has to be created.
       
   683     // This should not happen unless the message store is corrupted
       
   684     if ( mmsFolderId == KMsvNullIndexEntryId )
       
   685         {
       
   686         mmsFolderId = CreateMMSFolderL();
       
   687         }
       
   688 
       
   689     return mmsFolderId;
       
   690     }
       
   691 
       
   692 // -----------------------------------------------------------------------------
       
   693 // CMmsPushHandler::CreateMMSFolderL
       
   694 // Creates MMSNotifications folder into Message Store.
       
   695 // (As a subfolder of LocalService.)
       
   696 // Returns: <new TMsvId>: Entry Id of the created MMS folder.
       
   697 // -----------------------------------------------------------------------------
       
   698 //
       
   699 TMsvId CMmsPushHandler::CreateMMSFolderL()
       
   700     {
       
   701     LOGTEXT( _L("CreateMMSFolderL()") );
       
   702     //
       
   703     // Create entry
       
   704     //
       
   705     TMsvEntry entry;
       
   706     entry.iType = KUidMsvFolderEntry;
       
   707     entry.iMtm = KUidMsvLocalServiceMtm;
       
   708     entry.iDetails.Set( KMMSNotificationFolder );
       
   709     entry.SetVisible( EFalse );
       
   710     entry.SetInPreparation( EFalse );
       
   711     entry.iServiceId = KMsvLocalServiceIndexEntryId;
       
   712 
       
   713     //
       
   714     // Make the created entry to be a subfolder of LocalService
       
   715     //
       
   716     CMsvEntry* cMsvEntry 
       
   717         = iMsvSession->GetEntryL( KMsvLocalServiceIndexEntryId );
       
   718     CleanupStack::PushL( cMsvEntry );
       
   719     cMsvEntry->CreateL( entry );
       
   720     CleanupStack::PopAndDestroy( cMsvEntry );
       
   721 
       
   722     return entry.Id();
       
   723     }
       
   724 
       
   725 
       
   726 // -----------------------------------------------------------------------------
       
   727 // CMmsPushHandler::FindMMSFolderL
       
   728 // Checks if MMS folder entry already exists.
       
   729 // Returns: KMMSNotificationFolder: Entry Id of the found MMS folder
       
   730 //          KMsvNullIndexEntryId:   MMS folder was not found
       
   731 // -----------------------------------------------------------------------------
       
   732 //
       
   733 TMsvId CMmsPushHandler::FindMMSFolderL()
       
   734     {
       
   735     LOGTEXT( _L("FindMMSFolderL()") );
       
   736 
       
   737     TMsvId mmsFolderId = KMsvNullIndexEntryId;
       
   738 
       
   739     // Get Local Service as parent entry
       
   740     CMsvEntry* cMsvEntry = iMsvSession->GetEntryL( KMsvLocalServiceIndexEntryId );
       
   741     CleanupStack::PushL( cMsvEntry );
       
   742     // show invisible entries
       
   743     cMsvEntry->SetSortTypeL( TMsvSelectionOrdering( KMsvNoGrouping, 
       
   744                                                     EMsvSortByIdReverse, 
       
   745                                                     ETrue ) );
       
   746     // Get all folder entries.                                                    
       
   747     CMsvEntrySelection* selection 
       
   748         = cMsvEntry->ChildrenWithTypeL( KUidMsvFolderEntry );
       
   749     CleanupStack::PushL( selection );
       
   750 
       
   751     // Now we should have a list of all local folders.
       
   752     // Prune away the standard folders.
       
   753     // They should be at the end of the list
       
   754     TInt count = selection->Count();
       
   755     TInt i;
       
   756     for ( i = count - 1; i >= 0; i-- )
       
   757         {
       
   758         if ( selection->At( i ) <= KMsvDeletedEntryFolderEntryId )
       
   759             {
       
   760             // Anything below this should not be ours
       
   761             selection->Delete( i );
       
   762             }
       
   763         }
       
   764 
       
   765     // Check if anything left.
       
   766     count = selection->Count();
       
   767     // Loop through the rest and find possible correct folder
       
   768     for ( i = 0; i < count && mmsFolderId == KMsvNullIndexEntryId; i++ )
       
   769         {
       
   770         cMsvEntry->SetEntryL( selection->At( i ) );
       
   771         // must be exact match
       
   772         if (cMsvEntry->Entry().iDetails.Compare( KMMSNotificationFolder ) == 0)
       
   773             {
       
   774             mmsFolderId = selection->At( i );
       
   775             }
       
   776         }
       
   777     CleanupStack::PopAndDestroy( selection );
       
   778     CleanupStack::PopAndDestroy( cMsvEntry );
       
   779 
       
   780     // If folder does not exist -> returns KMsvNullIndexEntryId
       
   781     // If folder exists -> returns its Id
       
   782     return mmsFolderId;
       
   783     }
       
   784 
       
   785 // -----------------------------------------------------------------------------
       
   786 // CMmsPushHandler::CreateEntryL
       
   787 // 
       
   788 // -----------------------------------------------------------------------------
       
   789 //
       
   790 TMsvId CMmsPushHandler::CreateEntryL( TMsvId aFolder )
       
   791     {
       
   792     LOGTEXT( _L("CreateEntryL()") );
       
   793     //
       
   794     // Basic "NULL test"
       
   795     //
       
   796     if( aFolder == KMsvNullIndexEntryId )
       
   797         {
       
   798         // No folder, no entry
       
   799         return KMsvNullIndexEntryId;
       
   800         }
       
   801 
       
   802     //
       
   803     // Get CMsvEntry context of the target folder
       
   804     //
       
   805     CMsvEntry* cMsvEntry = iMsvSession->GetEntryL( aFolder );
       
   806     CleanupStack::PushL( cMsvEntry ); // ***
       
   807 
       
   808     //
       
   809     // Create an entry representing the notification
       
   810     //
       
   811     TMsvEntry tMsvEntry;
       
   812     tMsvEntry.iType = KUidMsvMessageEntry;
       
   813     tMsvEntry.iMtm = KUidMsgTypeMultimedia;
       
   814     tMsvEntry.iServiceId = KMsvLocalServiceIndexEntryId;
       
   815     tMsvEntry.iRelatedId = iServiceId;
       
   816     tMsvEntry.iMtmData2 = KMmsNotificationBinary;
       
   817     // Visible and inPreparation flags will be changed after data has been
       
   818     // successfully streamed
       
   819     tMsvEntry.SetVisible( EFalse );
       
   820     tMsvEntry.SetInPreparation( ETrue );
       
   821     cMsvEntry->CreateL( tMsvEntry );
       
   822 
       
   823     //
       
   824     // Stream 
       
   825     // 1) length of the data as 32 bit integer
       
   826     // 2) pushed message data
       
   827     // into created entry's stream  
       
   828     //
       
   829     cMsvEntry->SetEntryL( tMsvEntry.Id() );
       
   830     CMsvStore* store = cMsvEntry->EditStoreL();
       
   831     CleanupStack::PushL( store );   // ***
       
   832     RMsvWriteStream outs;
       
   833     outs.AssignLC( *store, KUidBinaryNotificationStream ); // ***
       
   834     outs.WriteUint32L( iBody->Size() );
       
   835     LOGTEXT2( _L(" - streamed %d bytes into dummy-entry's store"), iBody->Size() );
       
   836     outs.WriteL( *iBody );
       
   837     outs.CommitL();
       
   838     outs.Close();
       
   839     store->CommitL();
       
   840     CleanupStack::PopAndDestroy( &outs );  //outs
       
   841     CleanupStack::PopAndDestroy( store );
       
   842     //
       
   843     // Now, change the flags to their final values
       
   844     //
       
   845     tMsvEntry.SetVisible( ETrue );
       
   846     tMsvEntry.SetInPreparation( EFalse );
       
   847     cMsvEntry->ChangeL( tMsvEntry );
       
   848     CleanupStack::PopAndDestroy( cMsvEntry );  
       
   849 
       
   850     return tMsvEntry.Id();
       
   851     }
       
   852 
       
   853 // ========================== OTHER EXPORTED FUNCTIONS =========================
       
   854 
       
   855 // -----------------------------------------------------------------------------
       
   856 // ImplementationGroupProxy
       
   857 // Returns: TImplementationProxy*: Implementation table to the ECOM framework 
       
   858 // -----------------------------------------------------------------------------
       
   859 //
       
   860 EXPORT_C const TImplementationProxy* ImplementationGroupProxy( TInt& aTableCount )
       
   861     {
       
   862     aTableCount = sizeof( ImplementationTable ) / sizeof( TImplementationProxy );
       
   863 
       
   864     return ImplementationTable;
       
   865     }
       
   866 
       
   867 //  End of File