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