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