mmsengine/mmsserver/src/mmsserver.cpp
changeset 0 72b543305e3a
child 23 238255e8b033
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:  
       
    15 *     Server Mtm
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 // INCLUDE FILES
       
    22 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    23 #include <logengdurations.h>
       
    24 #endif
       
    25 #include    <apparc.h>
       
    26 #include    <msventry.h>
       
    27 #include    <msvschedulepackage.h>
       
    28 #include    <msvschedulesettings.h>
       
    29 #include    <msvsenderroraction.h>
       
    30 #include    <bautils.h>
       
    31 #include    <e32math.h> // for notification generation
       
    32 #include    <logcli.h>
       
    33 #include    <logview.h>
       
    34 #include    <flogger.h>
       
    35 #include    <e32svr.h>
       
    36 #include    <centralrepository.h>
       
    37 #include    <utf.h>
       
    38 #include    <cmsvmimeheaders.h>
       
    39 #include    <LogsApiConsts.h>
       
    40 
       
    41 
       
    42 // MMS specific
       
    43 #include    "mmsconst.h"
       
    44 #include    "mmserrors.h"
       
    45 #include    "mmsmmboxmessageheaders.h"
       
    46 #include    "mmsservercommon.h"
       
    47 #include    "mmscmds.h"
       
    48 #include    "mmssettings.h"
       
    49 #include    "mmsaccount.h"
       
    50 #include    "mmsserver.h"
       
    51 #include    "mmssendoperation.h"
       
    52 #include    "mmsreceivemessage.h"
       
    53 #include    "mmsforwardoperation.h"
       
    54 #include    "mmsdeleteoperation.h"
       
    55 #include    "mmsmmboxlist.h"
       
    56 #include    "mmsdecode.h"
       
    57 #include    "mmsencode.h"
       
    58 #include    "mmsheaders.h"
       
    59 #include    "mmsschedulesend.h"
       
    60 #include    "mmsscheduledentry.h"
       
    61 #include    "mmslog.h"
       
    62 #include    "mmsgenutils.h"
       
    63 #include    "mmsserverentry.h"
       
    64 #include    "MmsEnginePrivateCRKeys.h"
       
    65 #include    "mmsreadreport.h"
       
    66 
       
    67 // LOCAL CONSTANTS AND MACROS
       
    68 const TInt KMmsGarbageCollectionDelay = 30; // 30s delay
       
    69 const TInt KMmsSanityInterval = 96;  // 96 hours, 4 days
       
    70 const TInt KMmsScheduleAllowance = 10;
       
    71 const TInt KMmsScheduleDelay = 5;
       
    72 
       
    73 // ================= MEMBER FUNCTIONS =======================
       
    74 
       
    75 // ---------------------------------------------------------
       
    76 // C++ default constructor can NOT contain any code, that
       
    77 // might leave.
       
    78 // ---------------------------------------------------------
       
    79 //
       
    80 CMmsServerMtm::CMmsServerMtm(
       
    81     CRegisteredMtmDll& aRegisteredMtmDll,
       
    82     CMsvServerEntry* aInitialEntry )
       
    83     : CScheduleBaseServerMtm( aRegisteredMtmDll, aInitialEntry ),
       
    84     iNotification ( KMsvNullIndexEntryId ),
       
    85     iOOMState ( EFalse ),
       
    86     iDeliveryStatus (EFalse)
       
    87     {
       
    88     // Everything not mentioned gets initialized to NULL
       
    89     // Save our initial entry id
       
    90     // It is either default service or service specified in Entry Selection
       
    91     iServiceEntryId = aInitialEntry->Entry().Id();
       
    92     // We use the file session offered by initial entry.
       
    93     // Documentation says that it is expensive to open new file sessions
       
    94     // We offer the same session to all classes we create so that everybody
       
    95     // is using the same session.
       
    96     // In the final version file session is needed for attachment access
       
    97     // only, in the preliminary version we have a fake MMSC set up in a
       
    98     // directory on disk, and we need the file session to access that.
       
    99     iFs = aInitialEntry->FileSession();
       
   100     CActiveScheduler::Add( this );
       
   101     }
       
   102 
       
   103 // ---------------------------------------------------------
       
   104 // Symbian OS default constructor can leave.
       
   105 // 
       
   106 // ---------------------------------------------------------
       
   107 //
       
   108 void CMmsServerMtm::ConstructL()
       
   109     {
       
   110 
       
   111     CScheduleBaseServerMtm::ConstructL();
       
   112     iScheduleSend = CMmsScheduleSend::NewL( *iServerEntry );
       
   113     iMsvSelection = new( ELeave ) CMsvEntrySelection;
       
   114     iMmsSettings = CMmsSettings::NewL();
       
   115     // don't load settings yet in case someone else is trying
       
   116     // to change the settings.
       
   117     iMmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
       
   118     iMessageDrive = EDriveC;
       
   119     // see if message server knows better
       
   120     iMessageDrive = MessageServer::CurrentDriveL( iFs );
       
   121     }
       
   122 
       
   123 // ---------------------------------------------------------
       
   124 // Factory function
       
   125 // 
       
   126 // ---------------------------------------------------------
       
   127 //
       
   128 EXPORT_C CMmsServerMtm* CMmsServerMtm::NewL(
       
   129     CRegisteredMtmDll& aRegisteredMtmDll,
       
   130     CMsvServerEntry* aInitialEntry )
       
   131     {
       
   132     
       
   133     CleanupStack::PushL( aInitialEntry ); // Take ownership of aInitialEntry
       
   134     CMmsServerMtm* self = new( ELeave ) CMmsServerMtm(
       
   135         aRegisteredMtmDll, aInitialEntry );
       
   136     CleanupStack::Pop( aInitialEntry ); // Entry now safely stored in member
       
   137 
       
   138     CleanupStack::PushL( self );
       
   139     self->ConstructL();
       
   140     CleanupStack::Pop( self );
       
   141 
       
   142     return self;
       
   143     }
       
   144 
       
   145     
       
   146 // ---------------------------------------------------------
       
   147 // Destructor
       
   148 // 
       
   149 // ---------------------------------------------------------
       
   150 //
       
   151 CMmsServerMtm::~CMmsServerMtm()
       
   152     {
       
   153     // We don't close the file session anymore, as we
       
   154     // obtained if from the initial entry, and it is not ours to close...
       
   155     Cancel(); // cancel anything that may be pending...
       
   156     if ( iRemoteParties )
       
   157         {
       
   158         iRemoteParties->Reset();
       
   159         }
       
   160     delete iEntryWrapper;
       
   161     delete iRemoteParties;
       
   162     delete iReadReport;
       
   163     delete iSendOperation;
       
   164     delete iReceiveMessage;
       
   165     delete iForwardOperation;
       
   166     delete iDeleteOperation;
       
   167     delete iUpdateMmboxList;
       
   168     delete iMsvSelection;
       
   169     delete iMmsSettings;
       
   170     delete iScheduleSend;
       
   171     delete iDecoder;
       
   172     delete iMmsHeaders;
       
   173     delete iEncodeBuffer;
       
   174     delete iMmsLog;
       
   175     delete iLogEvent;
       
   176     delete iLogViewEvent;
       
   177     delete iLogClient;
       
   178 #ifndef _NO_MMSS_LOGGING_
       
   179     TMmsLogger::Log( _L("MMSServer destructor, done") );
       
   180 #endif
       
   181     }
       
   182 
       
   183 
       
   184 // ---------------------------------------------------------
       
   185 // CMmsServerMtm::CopyToLocalL
       
   186 // 
       
   187 // ---------------------------------------------------------
       
   188 //
       
   189 void CMmsServerMtm::CopyToLocalL(
       
   190     const CMsvEntrySelection& /*aSelection*/,
       
   191     TMsvId /*aDestination*/,
       
   192     TRequestStatus& aStatus )
       
   193     {
       
   194     
       
   195     TRequestStatus* status = &aStatus;
       
   196     aStatus = KRequestPending;
       
   197     User::RequestComplete( status, KErrNotSupported );
       
   198 
       
   199     }
       
   200 
       
   201 // ---------------------------------------------------------
       
   202 // CMmsServerMtm::CopyFromLocalL
       
   203 // 
       
   204 // ---------------------------------------------------------
       
   205 //
       
   206 void CMmsServerMtm::CopyFromLocalL(
       
   207     const CMsvEntrySelection& aSelection,
       
   208     TMsvId /*aDestination*/,
       
   209     TRequestStatus& aStatus )
       
   210     {
       
   211 
       
   212     // test code: copy from local means send.
       
   213     // sent folder is handled separately
       
   214     TCommandParameters parameters;
       
   215     parameters.iInitialDelay = 0;
       
   216     TCommandParametersBuf paramPack( parameters );
       
   217 
       
   218     CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
   219     CleanupStack::PushL(selection);
       
   220     if ( aSelection.Count() > 0 )
       
   221         {
       
   222         selection->AppendL( aSelection.Back( 0 ), aSelection.Count() );
       
   223         }
       
   224     StartCommandL( *selection, EMmsScheduledSend, paramPack, aStatus );
       
   225     CleanupStack::PopAndDestroy( selection );
       
   226   
       
   227     }
       
   228 
       
   229 // ---------------------------------------------------------
       
   230 // CMmsServerMtm::CopyWithinServiceL
       
   231 // 
       
   232 // ---------------------------------------------------------
       
   233 //
       
   234 void CMmsServerMtm::CopyWithinServiceL(
       
   235     const CMsvEntrySelection& /*aSelection*/,
       
   236     TMsvId /*aDestination*/,
       
   237     TRequestStatus& aStatus )
       
   238     {
       
   239 
       
   240     TRequestStatus* status = &aStatus;
       
   241     aStatus = KRequestPending;
       
   242     User::RequestComplete( status, KErrNotSupported );
       
   243 
       
   244     }
       
   245 
       
   246 // ---------------------------------------------------------
       
   247 // CMmsServerMtm::MoveToLocalL
       
   248 // 
       
   249 // ---------------------------------------------------------
       
   250 //
       
   251 void CMmsServerMtm::MoveToLocalL(
       
   252     const CMsvEntrySelection& /*aSelection*/,
       
   253     TMsvId /*aDestination*/,
       
   254     TRequestStatus& aStatus )
       
   255     {
       
   256 
       
   257     TRequestStatus* status = &aStatus;
       
   258     aStatus = KRequestPending;
       
   259     User::RequestComplete( status, KErrNotSupported );
       
   260 
       
   261     }
       
   262 
       
   263 // ---------------------------------------------------------
       
   264 // CMmsServerMtm::MoveFromLocalL
       
   265 // 
       
   266 // ---------------------------------------------------------
       
   267 //
       
   268 void CMmsServerMtm::MoveFromLocalL(
       
   269     const CMsvEntrySelection& /*aSelection*/,
       
   270     TMsvId /*aDestination*/,
       
   271     TRequestStatus& aStatus )
       
   272     {
       
   273 
       
   274     TRequestStatus* status = &aStatus;
       
   275     aStatus = KRequestPending;
       
   276     User::RequestComplete( status, KErrNotSupported );
       
   277 
       
   278     }
       
   279 
       
   280 // ---------------------------------------------------------
       
   281 // CMmsServerMtm::MoveWithinServiceL
       
   282 // 
       
   283 // ---------------------------------------------------------
       
   284 //
       
   285 void CMmsServerMtm::MoveWithinServiceL(
       
   286     const CMsvEntrySelection& /*aSelection*/,
       
   287     TMsvId /*aDestination*/,
       
   288     TRequestStatus& aStatus )
       
   289     {
       
   290 
       
   291     TRequestStatus* status = &aStatus;
       
   292     aStatus = KRequestPending;
       
   293     User::RequestComplete( status, KErrNotSupported );
       
   294 
       
   295     }
       
   296 
       
   297 // ---------------------------------------------------------
       
   298 // CMmsServerMtm::DeleteAllL
       
   299 // 
       
   300 // ---------------------------------------------------------
       
   301 //
       
   302 void CMmsServerMtm::DeleteAllL(
       
   303     const CMsvEntrySelection& aSelection,
       
   304     TRequestStatus& aStatus )
       
   305     {
       
   306 
       
   307     // this is implemented for scheduled send
       
   308     // It needs to change entry asynchronously,
       
   309     // and needs help on server mtm
       
   310     TInt error;
       
   311     // we are always called with a selection that has at least one member.
       
   312     // we cannot be called with an empty selection (because then the server
       
   313     // does not know whom to call)
       
   314     if ( aSelection.Count() == 0 )
       
   315         {
       
   316         User::Leave( KErrNotFound );
       
   317         }
       
   318     User::LeaveIfError( iServerEntry->SetEntry( aSelection[0] ) );
       
   319     User::LeaveIfError( iServerEntry->SetEntry( iServerEntry->Entry().Parent() ) );
       
   320     CMsvEntrySelection* sel = aSelection.CopyL();
       
   321     error = iServerEntry->DeleteEntries( *sel );
       
   322     if ( error == KErrNotFound )
       
   323         {
       
   324         error = KErrNone; // if not found, deleted already.
       
   325         }
       
   326     delete sel;
       
   327 
       
   328     TRequestStatus* status = &aStatus;
       
   329     aStatus = KRequestPending;
       
   330     User::RequestComplete( status, error );
       
   331     }
       
   332 
       
   333 // ---------------------------------------------------------
       
   334 // CMmsServerMtm::CreateL
       
   335 // 
       
   336 // ---------------------------------------------------------
       
   337 //
       
   338 void CMmsServerMtm::CreateL(
       
   339     TMsvEntry /*aNewEntry*/,
       
   340     TRequestStatus& aStatus )
       
   341     {
       
   342 
       
   343     TRequestStatus* status = &aStatus;
       
   344     aStatus = KRequestPending;
       
   345     User::RequestComplete( status, KErrNotSupported );
       
   346 
       
   347     }
       
   348 
       
   349 // ---------------------------------------------------------
       
   350 // CMmsServerMtm::ChangeL
       
   351 // 
       
   352 // ---------------------------------------------------------
       
   353 //
       
   354 void CMmsServerMtm::ChangeL(
       
   355     TMsvEntry aNewEntry,
       
   356     TRequestStatus& aStatus )
       
   357     {
       
   358 
       
   359     // this is implemented for scheduled send
       
   360     // It needs to change entry asynchronously,
       
   361     // and needs help on server mtm
       
   362     User::LeaveIfError( iServerEntry->SetEntry( aNewEntry.Id() ));
       
   363     User::LeaveIfError( iServerEntry->ChangeEntry( aNewEntry ) );
       
   364     TRequestStatus* status = &aStatus;
       
   365     aStatus = KRequestPending;
       
   366     User::RequestComplete( status, KErrNone );
       
   367 
       
   368     }
       
   369 
       
   370 // ---------------------------------------------------------
       
   371 // CMmsServerMtm::StartCommandL
       
   372 // 
       
   373 // ---------------------------------------------------------
       
   374 //
       
   375 void CMmsServerMtm::StartCommandL(
       
   376     CMsvEntrySelection& aSelection,
       
   377     TInt aCommand,
       
   378     const TDesC8& aParameter,
       
   379     TRequestStatus& aStatus )
       
   380     {
       
   381     
       
   382     TInt error = KErrNone;
       
   383     TMsvEntry entry; // This will be used a lot later to access the index data
       
   384     
       
   385 #ifndef _NO_MMSS_LOGGING_
       
   386     TMmsLogger::Log( _L("MMSServer Start Command %d"), aCommand );
       
   387 #endif // _NO_MMSS_LOGGING_
       
   388     // log the code for debugging
       
   389     LogCommandCode( aCommand );
       
   390     
       
   391     // The content of the parameter depends on command.
       
   392     // For EMmsDecodePushedMessage it will be TWatcherParametersBuf structure,
       
   393     // but the content is currently ignored because it has become impossible
       
   394     // to copy the data between processes in the protected environment.
       
   395     // For EMmsScheduledSend, EMmsScheduledReceive, and EMmsScheduledReceiveForced
       
   396     // it will be TCommandParametersBuf.
       
   397     // For EMmsGarbageCollection it will be TMMSGarbageCollectionParametersBuf
       
   398     // containing the reason for the garbage collection.
       
   399     // For others the parameter will be ignored.
       
   400     // The parameter should be unpackaged only when the contents are known.
       
   401 
       
   402     // The default service entry is always used.
       
   403 
       
   404     // Because of the restriction that only one mtm
       
   405     // per service can be open at any time, the scheduling calls
       
   406     // cheat and offer the stuff here using local service instead
       
   407     // of mms service. As we would like to load our settings
       
   408     // anyway, we try to find out the real service.
       
   409 
       
   410     if ( iServiceEntryId == KMsvLocalServiceIndexEntryId )
       
   411         {
       
   412         // we have been cheated
       
   413 #ifndef _NO_MMSS_LOGGING_
       
   414         TMmsLogger::Log( _L("- local service id") );
       
   415 #endif
       
   416         // Get the actual service id from a message entry
       
   417         GetRealServiceId( aSelection );
       
   418         }
       
   419         
       
   420     // free whatever entry we are holding
       
   421     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
   422 
       
   423     //
       
   424     // Load the service settings.
       
   425     // In case call fails, loading will be retried
       
   426     //
       
   427     TInt loadServiceError = KErrNone;
       
   428     TRAP( loadServiceError, LoadSettingsL( aCommand ) );
       
   429 
       
   430 #ifndef _NO_MMSS_LOGGING_
       
   431     if ( loadServiceError != KErrNone ) 
       
   432         {
       
   433         TMmsLogger::Log( _L("-ERROR loading settings: %d"), loadServiceError );
       
   434         }
       
   435     else
       
   436         {
       
   437         TMmsLogger::Log( _L("- settings loaded successfully") );        
       
   438         }
       
   439 #endif
       
   440 
       
   441     iCurrentCommand = aCommand;
       
   442     if ( aCommand != EMmsRetryServiceLoading )
       
   443         {
       
   444         iCommand = aCommand;
       
   445         iParameter = aParameter;
       
   446         iRequestStatus = &aStatus;
       
   447 
       
   448         // We remove the service entry from the selection, as we don't need it anymore
       
   449         iMsvSelection->Reset();
       
   450         if ( aSelection.Count() > 0 )
       
   451             {
       
   452             iMsvSelection->AppendL( aSelection.Back( 0 ), aSelection.Count() );
       
   453             }
       
   454         }
       
   455     else
       
   456         {
       
   457         // iRequestStatus was set on an earlier round.
       
   458         // EMmsRetryServiceLoading is never the first command
       
   459         iCurrentCommand = iCommand; // orginal command was stored here
       
   460         }
       
   461 
       
   462     // If service loading has failed, we loop through RunL to retry.
       
   463     // Actually only EMmsScheduledReceive and EMmsScheduledReceiveForced
       
   464     // need this service.
       
   465     // Other callers can handle error situations gracefully.
       
   466     // We have saved all our parameters.
       
   467     // All we have to do now is to change iCurrent command and complete ourselves
       
   468     // In order to get to our RunL.
       
   469     // RunL will route us to DoRunL where we can continue
       
   470 
       
   471     if ( loadServiceError != KErrNone )
       
   472         {
       
   473         // Actually we should no longer get load service error as the settings
       
   474         // are now in central repository, no longer saved into the service entry
       
   475         HandleLoadServiceError( loadServiceError );
       
   476         // we cannot continue. HandleLoadServiceError has set completion status
       
   477         // as required.
       
   478         return;
       
   479         }
       
   480 
       
   481     // If we have loaded the service, we can discard the service entry
       
   482     // if it still is in our selection
       
   483     if ( iMsvSelection->Count() > 0 && iMsvSelection->At( 0 ) == iServiceEntryId )
       
   484         {
       
   485         iMsvSelection->Delete( 0 ); 
       
   486         }
       
   487 
       
   488 #ifndef _NO_MMSS_LOGGING_
       
   489     // log the parent folder of the selection (needed for debugging)
       
   490     LogEntryParent();
       
   491 #endif
       
   492 
       
   493     // we do not move the entries anywhere.
       
   494     // it is the client's responsibility to move them to the right place
       
   495     // we just make them visible because some applications left invisible
       
   496     // entries to outbox.
       
   497     if ( iCurrentCommand == EMmsSend ||
       
   498         iCurrentCommand == EMmsScheduledSend ||
       
   499         iCurrentCommand == EMmsDeleteSchedule )
       
   500         {
       
   501         RestoreVisibilityAndService();
       
   502         }
       
   503 
       
   504     //
       
   505     // Following switch handles all the different requests
       
   506     //
       
   507     switch( iCurrentCommand )
       
   508         {
       
   509         // scheduled operations can only use default service.
       
   510         case EMmsScheduledSend:
       
   511             if ( iMsvSelection->Count() > 0 )
       
   512                 {
       
   513                 iCommand = EMmsSend;
       
   514                 // This will complete our caller.
       
   515                 // If no error, task scheduler will complete the caller.
       
   516                 // If error, the subroutine will complete
       
   517                 error = ScheduleSelectionL();
       
   518 #ifndef _NO_MMSS_LOGGING_
       
   519                 if ( error != KErrNone )
       
   520                     {
       
   521                     TMmsLogger::Log( _L("MmsServer Schedule send status %d"), error );
       
   522                     }
       
   523 #endif
       
   524                 }
       
   525             else
       
   526                 {
       
   527                 // nothing to send - successfully sent nothing
       
   528                 // ("You must have keen eyes to see nobody coming")
       
   529                 *iRequestStatus = KRequestPending;
       
   530                 User::RequestComplete( iRequestStatus, KErrNone );
       
   531                 }
       
   532             break;
       
   533         //
       
   534         // Handle push message (i.e. notification or delivery report)
       
   535         //
       
   536         case EMmsDecodePushedMessage:
       
   537             {
       
   538             // 
       
   539             // First read pushed data from dummy entries stream store,
       
   540             // and then delete it.
       
   541             // If there is no entry, HandleDummyEntryL() leaves
       
   542             // 
       
   543             HandleDummyEntryL();
       
   544             //
       
   545             // Decode received databuffer into message
       
   546             //
       
   547             TInt err = KErrNone;
       
   548             TRAP( err, DecodePushedMessageL() );
       
   549             // DecodePushedMessageL might set iError, don't override it
       
   550             if ( iError == KErrNone )
       
   551                 {
       
   552                 iError = err;
       
   553                 }
       
   554 
       
   555             delete iEncodeBuffer;
       
   556             iEncodeBuffer = NULL;
       
   557             // The resulting id is now in iNotification
       
   558 
       
   559             if ( iNotification != KMsvNullIndexEntryId )
       
   560                 {
       
   561                 iMsvSelection->AppendL( iNotification );
       
   562                 if ( iServerEntry->SetEntry( iNotification ) == KErrNone )
       
   563                     {
       
   564                     entry = iServerEntry->Entry();
       
   565                     }
       
   566                 // Unrecognized PDUs are handled as notifications.
       
   567                 // we send a response back to MMSC
       
   568                 if ( ( ( entry.iMtmData1 & KMmsMessageTypeMask ) == KMmsMessageDeliveryInd ) ||
       
   569                     ( ( entry.iMtmData1 & KMmsMessageTypeMask ) == KMmsMessageReadOrigInd ) )
       
   570                     {
       
   571                     // Delivery report or PDU read report
       
   572                     HandleDeliveryReportL();
       
   573                     }
       
   574                 else
       
   575                     {
       
   576                     // Everything else. Handle as notification.
       
   577                     // If not a notification, send back response "unrecognized"
       
   578                     // Any PDU with wrong type will fall here besides the actual notifications.
       
   579                     HandleNotificationL();
       
   580                     }
       
   581                 }
       
   582             else
       
   583                 {
       
   584                 // something has gone wrong...
       
   585                 *iRequestStatus = KRequestPending;
       
   586                 User::RequestComplete( iRequestStatus, iError );
       
   587                 }
       
   588             break;
       
   589             }
       
   590         case EMmsScheduledReceiveForced:
       
   591             iCommand = EMmsReceiveForced;
       
   592             iMmsSettings->SetFetchOverride( ETrue );
       
   593             // if we do forced fetch, we clean up old schedules first
       
   594             if ( iMsvSelection->Count() > 0 )
       
   595                 {
       
   596                 CleanSchedulesL( *iMsvSelection );
       
   597                 }
       
   598             // fall through on purpose
       
   599         case EMmsScheduledReceive:
       
   600             if ( iCurrentCommand != EMmsScheduledReceiveForced )
       
   601                 {
       
   602                 iCommand = EMmsReceive;
       
   603                 }
       
   604             if ( iMsvSelection->Count() < 1 )
       
   605                 {
       
   606                 TRAP( iError, CreateNotificationsL() );
       
   607                 }
       
   608             else // iMsvSelection->Count() > 0 
       
   609                 {
       
   610                 // notifications are not checked if the fetch is forced
       
   611                 if ( iCurrentCommand == EMmsScheduledReceive )
       
   612                     {
       
   613                     CheckNotificationsL( *iMsvSelection );
       
   614                     }
       
   615                 }
       
   616 
       
   617             if ( iMsvSelection->Count() > 0 )
       
   618                 {
       
   619                 // This will complete our caller.
       
   620                 // If no error, task scheduler will complete the caller.
       
   621                 // If error, the subroutine will complete
       
   622                 error = ScheduleSelectionL();
       
   623 #ifndef _NO_MMSS_LOGGING_
       
   624                 if ( error != KErrNone )
       
   625                     {
       
   626                     TMmsLogger::Log( _L("MmsServer Schedule receive status %d"), error );
       
   627                     }
       
   628 #endif
       
   629                 }
       
   630             else
       
   631                 {
       
   632                 // Nothing to be done, complete.
       
   633                 if ( iError != KErrNoMemory && iError != KErrDiskFull )
       
   634                     {
       
   635                     iError = KErrNone;
       
   636                     }
       
   637                 *iRequestStatus = KRequestPending;
       
   638                 User::RequestComplete( iRequestStatus, iError );
       
   639                 }
       
   640             break;
       
   641         case EMmsSend:
       
   642             // send messages in current selection
       
   643             // we cannot do this, if we don't have settings.
       
   644             // Our access point is defined in settings.
       
   645 #ifndef _NO_MMSS_LOGGING_
       
   646             TMmsLogger::Log( _L("Number of entries to send %d"), iMsvSelection->Count() );
       
   647 #endif
       
   648             if ( iMsvSelection->Count() == 0 )
       
   649                 {
       
   650                 // nothing in the selection...
       
   651                 *iRequestStatus = KRequestPending;
       
   652                 User::RequestComplete( iRequestStatus, KErrNone );
       
   653                 }
       
   654             else
       
   655                 {
       
   656                 iCommand = EMmsSend;
       
   657                 SendToMmscL();
       
   658                 }
       
   659             break;
       
   660         case EMmsReceive:
       
   661             // fetch message to inbox
       
   662             // This is a troublesome case.
       
   663             // we cannot fetch if we did not manage to load
       
   664             // our settings.
       
   665             // And we cannot leave, because schsend has an assert
       
   666             // that forbids rescheduling entries that are not children
       
   667             // of local service. And our notifications are children of
       
   668             // the MMS service itself.
       
   669             iCommand = EMmsReceive;
       
   670             FetchFromMmscL();
       
   671             break;
       
   672         case EMmsReceiveForced:
       
   673             iCommand = EMmsReceiveForced;
       
   674             iMmsSettings->SetFetchOverride( ETrue );
       
   675             FetchFromMmscL();
       
   676             break;
       
   677         case EMmsLogDeliveryReport:
       
   678             iCommand = EMmsLogDeliveryReport;
       
   679             // delivery reports should appear one by one for handling
       
   680             LogDeliveryReportL();
       
   681             break;
       
   682         case EMmsDeleteSchedule:
       
   683             iScheduleSend->DeleteScheduleL( aSelection );
       
   684             *iRequestStatus = KRequestPending;
       
   685             User::RequestComplete( iRequestStatus, KErrNone );
       
   686             break;
       
   687         case EMmsDeleteEntries:
       
   688             if ( iMsvSelection->Count() > 0 )
       
   689                 {
       
   690                 error = iServerEntry->SetEntry( iMsvSelection->At(0) );
       
   691                 if ( error == KErrNone )
       
   692                     {
       
   693                     error = iServerEntry->SetEntry( iServerEntry->Entry().Parent() );
       
   694                     if ( error == KErrNone )
       
   695                         {
       
   696                         error = iServerEntry->DeleteEntries( *iMsvSelection );
       
   697                         }
       
   698                     }
       
   699                 *iRequestStatus = KRequestPending;
       
   700                 User::RequestComplete( iRequestStatus, error );
       
   701                 }
       
   702             else
       
   703                 {
       
   704                 // if nothing to delete, then done already
       
   705                 *iRequestStatus = KRequestPending;
       
   706                 User::RequestComplete( iRequestStatus, KErrNone );
       
   707                 }
       
   708             break;
       
   709         case EMmsGarbageCollection:
       
   710             TRAP(error, GarbageCollectionL());
       
   711             // This returns at least KMmsErrorOfflineMode
       
   712             *iRequestStatus = KRequestPending;
       
   713             User::RequestComplete( iRequestStatus, error );
       
   714             break;
       
   715         case EMmsMessageGeneration:
       
   716             iCommand = EMmsReceiveForced;
       
   717             iMmsSettings->SetLocalModeIn( KMmsMessageVariationDirectory() );
       
   718             iMmsSettings->SetFetchOverride( ETrue );
       
   719             // set local mode on the fly - not stored anywhere.
       
   720             iMmsSettings->SetLocalMode( ETrue );
       
   721             iMmsSettings->SetAcceptAnonymousMessages( ETrue ); // variated messages are anonymous
       
   722             FetchFromMmscL();
       
   723             break;
       
   724         case EMmsDeleteExpiredNotifications:
       
   725             // not implemented
       
   726             *iRequestStatus = KRequestPending;
       
   727             User::RequestComplete( iRequestStatus, KErrNotSupported );
       
   728             break;
       
   729 
       
   730         case EMmsScheduledForward:
       
   731             // Make sure there is something to schedule
       
   732             if ( iMsvSelection->Count() > 0 )
       
   733                 {
       
   734                 iCommand = EMmsForward;
       
   735                 // ScheduleSelectionL completes the caller.
       
   736                 // If no error, task scheduler will complete the caller.
       
   737                 // If error, the subroutine will complete
       
   738                 error = ScheduleSelectionL();
       
   739 #ifndef _NO_MMSS_LOGGING_
       
   740                 if ( error != KErrNone )
       
   741                     {
       
   742                     TMmsLogger::Log( _L("MmsServer EMmsScheduledForward status %d"), error );
       
   743                     }
       
   744 #endif
       
   745                 }
       
   746             else
       
   747                 {
       
   748                 // Nothing to send
       
   749                 *iRequestStatus = KRequestPending;
       
   750                 User::RequestComplete( iRequestStatus, KErrNone );
       
   751                 }
       
   752             break;
       
   753 
       
   754         case EMmsForward:
       
   755             // Sends the current selection (containing forward requests)
       
   756             // we cannot do this, if we don't have settings.
       
   757             // Our access point is defined in settings.
       
   758 #ifndef _NO_MMSS_LOGGING_
       
   759             TMmsLogger::Log( _L("Number of forward requests to send %d"), iMsvSelection->Count() );
       
   760 #endif
       
   761             if ( iMsvSelection->Count() == 0 )
       
   762                 {
       
   763                 // Nothing in the selection
       
   764                 *iRequestStatus = KRequestPending;
       
   765                 User::RequestComplete( iRequestStatus, KErrNone );
       
   766                 }
       
   767             else
       
   768                 {
       
   769                 iCommand = EMmsForward;
       
   770                 SendForwardRequestsToMmscL();
       
   771                 }
       
   772             break;
       
   773 
       
   774         //
       
   775         // Handles scheduling of notification deletion
       
   776         // 
       
   777         case EMmsScheduledNotificationDelete:
       
   778             // Make sure there is something to schedule
       
   779             if ( iMsvSelection->Count() > 0 )
       
   780                 {
       
   781                 iCommand = EMmsNotificationDelete;
       
   782                 // ScheduleSelectionL completes the caller.
       
   783                 // If no error, task scheduler will complete the caller.
       
   784                 // If error, the subroutine will complete
       
   785                 error = ScheduleSelectionL();
       
   786 #ifndef _NO_MMSS_LOGGING_
       
   787                 if ( error != KErrNone )
       
   788                     {
       
   789                     TMmsLogger::Log( _L("MmsServer EMmsScheduledNotificationDelete status %d"), error );
       
   790                     }
       
   791 #endif
       
   792                 }
       
   793             else
       
   794                 {
       
   795                 // Nothing to schedule
       
   796                 *iRequestStatus = KRequestPending;
       
   797                 User::RequestComplete( iRequestStatus, KErrNone );
       
   798                 }
       
   799             break;
       
   800 
       
   801         //
       
   802         // Deletes selection of notifications
       
   803         //
       
   804         case EMmsNotificationDelete:
       
   805 #ifndef _NO_MMSS_LOGGING_
       
   806             TMmsLogger::Log( _L("Number of notifications to delete %d"), iMsvSelection->Count() );
       
   807 #endif
       
   808             if ( iMsvSelection->Count() == 0 )
       
   809                 {
       
   810                 // Nothing in the selection
       
   811                 *iRequestStatus = KRequestPending;
       
   812                 User::RequestComplete( iRequestStatus, KErrNone );
       
   813                 }
       
   814             else
       
   815                 {
       
   816                 iCommand = EMmsNotificationDelete;
       
   817 
       
   818                 // Dig out delete type
       
   819                 TCommandParameters param;
       
   820                 TPckgC<TCommandParameters> paramPack( param );
       
   821                 paramPack.Set( iParameter );
       
   822 
       
   823                 //
       
   824                 // Create a CMmsDeleteOperation instance and start it
       
   825                 // 
       
   826                 delete iDeleteOperation;
       
   827                 iDeleteOperation = NULL;
       
   828                 iDeleteOperation = CMmsDeleteOperation::NewL( iFs, iMmsSettings  );
       
   829                 iDeleteOperation->StartL(
       
   830                     (TMmsDeleteOperationType)paramPack().iError,
       
   831                     *iMsvSelection,
       
   832                     *iServerEntry,
       
   833                     iServiceEntryId,
       
   834                     iStatus );
       
   835                 *iRequestStatus = KRequestPending;
       
   836                 SetActive();        
       
   837                 }
       
   838             break;
       
   839             // update mmbox list
       
   840         case EMmsUpdateMmboxList:
       
   841             iCommand = EMmsUpdateMmboxList;
       
   842             delete iUpdateMmboxList;
       
   843             iUpdateMmboxList = NULL;
       
   844             iUpdateMmboxList = CMmsMmboxList::NewL( iFs, iMmsSettings );
       
   845             iUpdateMmboxList->StartL(
       
   846                 *iMsvSelection,
       
   847                 *iServerEntry,
       
   848                 iServiceEntryId, 
       
   849                 iStatus );
       
   850             *iRequestStatus = KRequestPending;
       
   851             SetActive();
       
   852             break;
       
   853         case EMmsSendReadReport:
       
   854             SendReadReportL();
       
   855             break;
       
   856         case EMmsScheduledReadReport:
       
   857             if ( iMsvSelection->Count() > 0 )
       
   858                 {
       
   859                 iCommand = EMmsSendReadReport;
       
   860                 // ScheduleSelectionL completes the caller.
       
   861                 // If no error, task scheduler will complete the caller.
       
   862                 // If error, the subroutine will complete
       
   863                 error = ScheduleSelectionL();
       
   864 #ifndef _NO_MMSS_LOGGING_
       
   865                 if ( error != KErrNone )
       
   866                     {
       
   867                     TMmsLogger::Log( _L("MmsServer EMmsScheduledReadReport status %d"), error );
       
   868                     }
       
   869 #endif
       
   870                 }
       
   871             else
       
   872                 {
       
   873                 // Nothing to schedule
       
   874                 *iRequestStatus = KRequestPending;
       
   875                 User::RequestComplete( iRequestStatus, KErrNone );
       
   876                 }
       
   877             break;
       
   878         default:
       
   879             *iRequestStatus = KRequestPending;
       
   880             User::RequestComplete( iRequestStatus, KErrNotSupported );
       
   881             break;
       
   882         }
       
   883     }
       
   884 
       
   885 // ---------------------------------------------------------
       
   886 // CMmsServerMtm::CommandExpected
       
   887 // 
       
   888 // ---------------------------------------------------------
       
   889 //
       
   890 TBool CMmsServerMtm::CommandExpected()
       
   891     {
       
   892     // so far we don't expect anything
       
   893 
       
   894     return EFalse;
       
   895 
       
   896     }
       
   897 
       
   898 // ---------------------------------------------------------
       
   899 // CMmsServerMtm::Progress
       
   900 // 
       
   901 // ---------------------------------------------------------
       
   902 //
       
   903 const TDesC8& CMmsServerMtm::Progress()
       
   904     {
       
   905     // should load in latest progress, if something is going on
       
   906 
       
   907     return iProgressBuffer;
       
   908 
       
   909     }        
       
   910 
       
   911 // ---------------------------------------------------------
       
   912 // CMmsServerMtm::LoadResourceFile
       
   913 // 
       
   914 // ---------------------------------------------------------
       
   915 //
       
   916 void CMmsServerMtm::LoadResourceFileL()
       
   917     {
       
   918     // THIS IS NO LONGER NEEDED, BECAUSE THERE IS NO RESOURCE FILE ANY MORE.
       
   919     }
       
   920 
       
   921 // ---------------------------------------------------------
       
   922 // CMmsServerMtm::PopulateSchedulePackage
       
   923 // ---------------------------------------------------------
       
   924 //
       
   925 void CMmsServerMtm::PopulateSchedulePackage( const TDesC8& aParameter,
       
   926     const TBool /*aMove*/, TMsvSchedulePackage& aPackage ) const
       
   927     {
       
   928     aPackage.iParameter = aParameter;
       
   929     // We have a member telling what we are supposed to do.
       
   930     // We can schedule both sending and receiving.
       
   931     aPackage.iCommandId =  iCommand;
       
   932     }
       
   933 
       
   934 // ---------------------------------------------------------
       
   935 // CMmsServerMtm::RestoreScheduleSettingsL
       
   936 // ---------------------------------------------------------
       
   937 //
       
   938 void CMmsServerMtm::RestoreScheduleSettingsL( 
       
   939     TBool /*aRestoreErrorsFromResource*/, 
       
   940     TInt /*aErrorsResourceId*/ )
       
   941     {
       
   942     // EMPTY IMPLEMENTATION
       
   943     }
       
   944 
       
   945 // ---------------------------------------------------------
       
   946 // CMmsServerMtm::DoCancel
       
   947 // 
       
   948 // ---------------------------------------------------------
       
   949 //
       
   950 void CMmsServerMtm::DoCancel()
       
   951     {
       
   952 
       
   953     // first cancel whatever operation is active
       
   954     if ( iSendOperation )
       
   955         {
       
   956         iSendOperation->Cancel();
       
   957         }
       
   958 
       
   959     if ( iReceiveMessage )
       
   960         {
       
   961         iReceiveMessage->Cancel();
       
   962         }
       
   963 
       
   964     if ( iMmsLog )
       
   965         {
       
   966         iMmsLog->Cancel();
       
   967         }
       
   968 
       
   969     if( iDeleteOperation )
       
   970         {
       
   971         iDeleteOperation->Cancel();
       
   972         }
       
   973 
       
   974     if( iForwardOperation )
       
   975         {
       
   976         iForwardOperation->Cancel();
       
   977         }
       
   978 
       
   979     if ( iUpdateMmboxList )
       
   980         {
       
   981         iUpdateMmboxList->Cancel();
       
   982         }
       
   983 
       
   984     if ( iReadReport )
       
   985         {
       
   986         iReadReport->Cancel();
       
   987         }
       
   988 
       
   989     DoComplete( KErrCancel );
       
   990 
       
   991     }
       
   992 
       
   993 // ---------------------------------------------------------
       
   994 // CMmsServerMtm::DoRunL
       
   995 // Active object completion
       
   996 // Run is used in this object to clean up after operations have finished.
       
   997 //
       
   998 // ---------------------------------------------------------
       
   999 //
       
  1000 void CMmsServerMtm::DoRunL()
       
  1001     {
       
  1002 #ifndef _NO_MMSS_LOGGING_
       
  1003     TMmsLogger::Log( _L(" MmsServer DoRunL status %d"), iStatus.Int() );
       
  1004 #endif
       
  1005 
       
  1006     if ( iCurrentCommand == EMmsRetryServiceLoading )
       
  1007         {
       
  1008         StartCommandL(
       
  1009             *iMsvSelection,
       
  1010             iCurrentCommand,
       
  1011             iParameter,
       
  1012             *iRequestStatus);
       
  1013         return;
       
  1014         }
       
  1015 
       
  1016     TInt error = KErrNone;
       
  1017 
       
  1018     if ( iOOMState ) // out of memory.
       
  1019         {
       
  1020         error = KErrNoMemory;
       
  1021         }
       
  1022         
       
  1023     if ( iCurrentCommand == EMmsUpdateMmboxList )
       
  1024         {
       
  1025         error = iStatus.Int();
       
  1026         }
       
  1027 
       
  1028     // When we come here, we must see, if everything
       
  1029     // was sent - or received, or if some items need resceduling
       
  1030     DoComplete( error );
       
  1031         
       
  1032     }
       
  1033 
       
  1034 // ---------------------------------------------------------
       
  1035 // CMmsServerMtm::DoComplete
       
  1036 // 
       
  1037 // Active object complete
       
  1038 // ---------------------------------------------------------
       
  1039 //
       
  1040 void CMmsServerMtm::DoComplete( TInt aError )
       
  1041     {
       
  1042 #ifndef _NO_MMSS_LOGGING_
       
  1043     TMmsLogger::Log( _L(" MmsServer DoComplete with status %d"), aError );
       
  1044 #endif
       
  1045 
       
  1046     // free whatever entry we were holding
       
  1047     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  1048 
       
  1049     // iSendOperation and iReceiveMessage tell us if
       
  1050     // we were sending or receiving. The one that is non-null
       
  1051     // has done all the work
       
  1052 
       
  1053     // Now we must check if all went fine, or do some entries
       
  1054     // need rescheduling.
       
  1055 
       
  1056     // In the case of sending iMsvSelection holds Ids of the
       
  1057     // messages to be sent. In the case of receiving iMsvSelection
       
  1058     // holds Ids of the notifications corresponding to messages
       
  1059     // to be fetched.
       
  1060 
       
  1061     TRAPD( error, UpdateEntriesL() );
       
  1062 
       
  1063 #ifdef __WINS__
       
  1064     if ( iSendOperation )
       
  1065         {
       
  1066         User::InfoPrint(_L("MMS sending complete"));
       
  1067         }
       
  1068     if ( iReceiveMessage )
       
  1069         {
       
  1070         User::InfoPrint(_L("MMS receiving complete"));
       
  1071         }
       
  1072 #endif
       
  1073 
       
  1074     // restore original entry
       
  1075     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  1076 
       
  1077     if ( iError == KErrNone )
       
  1078         {
       
  1079         // The error may be changed in UpdateEntriesL
       
  1080         iError = aError;
       
  1081         }
       
  1082       
       
  1083     if ( iError == KMmsErrorApplicationDiskFull )
       
  1084         {
       
  1085         // this was handled by restarting the fetch if possible
       
  1086         iError = KErrNone;
       
  1087         }
       
  1088         
       
  1089     if ( iError == KErrNone )
       
  1090         {
       
  1091         // Pass on the error from UpDateEntriesL if it is relevant
       
  1092         // to the caller.
       
  1093         // First all errors caused by simultaneous backup/restore
       
  1094         // are passed on.
       
  1095         // If the entries were successfully reschedules we should
       
  1096         // have no error here.
       
  1097         if ( error >= KMsvMediaUnavailable && error <= KMsvIndexRestore )
       
  1098             {
       
  1099             iError = error;
       
  1100             }
       
  1101         }
       
  1102 #ifndef _NO_MMSS_LOGGING_
       
  1103     TMmsLogger::Log( _L("MmsServer returns error: %d to caller" ), iError );
       
  1104 #endif
       
  1105     if ( !( IsActive() && iStatus.Int() == KRequestPending ) )
       
  1106         {
       
  1107         // If CMmsServer has become active again it means that it has restarted
       
  1108         // the fetch after deleting some application messages
       
  1109         // The restarted fetch will complete caller when finished
       
  1110         
       
  1111         // However, if any ongoing operation is cancelled prematurely,
       
  1112         // we may still be in active state but our own status is "cancelled"
       
  1113         
       
  1114         User::RequestComplete( iRequestStatus, iError );
       
  1115         }
       
  1116     }
       
  1117 
       
  1118 // ---------------------------------------------------------
       
  1119 // CMmsServerMtm::LoadSettingsL
       
  1120 // 
       
  1121 // ---------------------------------------------------------
       
  1122 //
       
  1123 void CMmsServerMtm::LoadSettingsL( TInt aCommand )
       
  1124     {
       
  1125     // Load settings
       
  1126     iMmsSettings->LoadSettingsL();
       
  1127 
       
  1128     // Save service entry id
       
  1129     iServiceEntryId = iMmsSettings->Service();
       
  1130     
       
  1131     // Make sure localmode related paths exist
       
  1132     if( iMmsSettings->LocalMode() )
       
  1133         {
       
  1134         iFs.MkDirAll( iMmsSettings->LocalModeIn() );
       
  1135         iFs.MkDirAll( iMmsSettings->LocalModeOut() );
       
  1136         }
       
  1137 
       
  1138     // Load schedule settings    
       
  1139     ((CMmsScheduleSend*)iScheduleSend)->LoadSettingsL( aCommand );
       
  1140     }
       
  1141 
       
  1142 // ---------------------------------------------------------
       
  1143 // CMmsServerMtm::SendToMmscL()
       
  1144 // 
       
  1145 // ---------------------------------------------------------
       
  1146 //
       
  1147 void CMmsServerMtm::SendToMmscL()
       
  1148     {
       
  1149     // We call our new excellent state machine
       
  1150     delete iSendOperation;
       
  1151     iSendOperation = NULL;
       
  1152     iSendOperation = CMmsSendOperation::NewL( iFs, iMmsSettings );
       
  1153     iSendOperation->StartL( *iMsvSelection, *iServerEntry, 
       
  1154         iServiceEntryId, iStatus );
       
  1155     *iRequestStatus = KRequestPending;
       
  1156     SetActive();
       
  1157     }
       
  1158 
       
  1159 // ---------------------------------------------------------
       
  1160 // CMmsServerMtm::SendForwardRequestsToMmscL()
       
  1161 // 
       
  1162 // ---------------------------------------------------------
       
  1163 //
       
  1164 void CMmsServerMtm::SendForwardRequestsToMmscL()
       
  1165     {
       
  1166     //
       
  1167     // Create a CMmsForwardOperation instance and start it
       
  1168     // 
       
  1169     delete iForwardOperation;
       
  1170     iForwardOperation = NULL;
       
  1171     iForwardOperation = CMmsForwardOperation::NewL( iFs, iMmsSettings );
       
  1172     iForwardOperation->StartL( 
       
  1173         *iMsvSelection, 
       
  1174         *iServerEntry, 
       
  1175         iServiceEntryId, 
       
  1176         iStatus );
       
  1177     *iRequestStatus = KRequestPending;
       
  1178     SetActive();        
       
  1179     }
       
  1180 
       
  1181 // ---------------------------------------------------------
       
  1182 // CMmsServerMtm::FetchFromMmscL()
       
  1183 // 
       
  1184 // ---------------------------------------------------------
       
  1185 //
       
  1186 void CMmsServerMtm::FetchFromMmscL()
       
  1187     {
       
  1188     // We must put notifications into the selection.
       
  1189     // The notifications will be have the same format
       
  1190     // as message entries, but they will contain only
       
  1191     // MMS headers.
       
  1192 
       
  1193     // The test version will use only the URI (Content-Location)
       
  1194     // from the notification.
       
  1195     // The Content-Location will contain the path and filename - 
       
  1196     // as the first approximation.
       
  1197 
       
  1198     // For test purposes we create a fake selection by scanning
       
  1199     // the directory specified in the settings, and storing the
       
  1200     // filenames as messages under current service.
       
  1201 
       
  1202     // If we have rescheduled entries, we don't create a new notification
       
  1203     // list, as we have one already
       
  1204     if ( iMsvSelection->Count() < 1 )
       
  1205         {
       
  1206         CreateNotificationsL();
       
  1207         }
       
  1208 
       
  1209     // If anything was left, we fetch them
       
  1210     if ( iMsvSelection->Count() > 0 )
       
  1211         {
       
  1212         // We call our new excellent state machine
       
  1213         delete iReceiveMessage;
       
  1214         iReceiveMessage = NULL;
       
  1215         iReceiveMessage = CMmsReceiveMessage::NewL( iFs, iMmsSettings  );
       
  1216 
       
  1217         iReceiveMessage->StartL( *iMsvSelection, *iServerEntry,
       
  1218             iServiceEntryId, iStatus );
       
  1219         if ( iRequestStatus->Int() != KRequestPending )
       
  1220             {
       
  1221             *iRequestStatus = KRequestPending;
       
  1222             }
       
  1223         SetActive();    
       
  1224         }
       
  1225     else
       
  1226         {
       
  1227         // We say we are done without error, if we pruned everything.
       
  1228         // The original notifications that caused the pruning should
       
  1229         // still be hanging around.
       
  1230         // There is a danger of fetching failing so often that
       
  1231         // we cannot even manage to send a response to MMSC, and
       
  1232         // it sends us a duplicate notification because it thinks
       
  1233         // the original one has got lost.
       
  1234         // We must carefully test the failure conditions and try to 
       
  1235         // determine reasonable amount of retries that should be done
       
  1236         // to avoid such situation.
       
  1237         // The other possibility would be to always remove the old
       
  1238         // notification if a new one arrives with identical TID and
       
  1239         // Content location, but then we would be in danger of
       
  1240         // deleting an entry that is currently being used to fetch
       
  1241         // a message.
       
  1242         // The actual fetching code in CMmsReceiveMessage class
       
  1243         // tries to test that the notifications are accessible,
       
  1244         // and it tries not to trap, if the notifications have
       
  1245         // disappeared from its lists,
       
  1246         if ( iError != KErrNoMemory &&
       
  1247             iError != KErrDiskFull && iError != KMmsErrorApplicationDiskFull )
       
  1248             {
       
  1249             iError = KErrNone;
       
  1250             }
       
  1251         if ( iRequestStatus->Int() != KRequestPending )
       
  1252             {
       
  1253             *iRequestStatus = KRequestPending;
       
  1254             }
       
  1255         if ( iError == KMmsErrorApplicationDiskFull )
       
  1256             {
       
  1257             // DoComplete will complete caller
       
  1258             iError = KErrNone; 
       
  1259             }
       
  1260         else
       
  1261             {
       
  1262             User::RequestComplete( iRequestStatus, iError );
       
  1263             }
       
  1264         }
       
  1265     }
       
  1266 
       
  1267 // ---------------------------------------------------------
       
  1268 // CMmsServerMtm::UpdateEntriesL()
       
  1269 // 
       
  1270 // ---------------------------------------------------------
       
  1271 //
       
  1272 void CMmsServerMtm::UpdateEntriesL()
       
  1273     {
       
  1274     // if something goes fatally wrong, this error will be
       
  1275     // returned to the caller in hope the caller may be able
       
  1276     // to do something to fix the problem
       
  1277     TInt fatalError = KErrNone; 
       
  1278     TMsvEntry entry;
       
  1279 #ifndef _NO_MMSS_LOGGING_
       
  1280     TMmsLogger::Log( _L("UpdateEntriesL" ));
       
  1281 #endif
       
  1282 
       
  1283     // Tell scheduler about entries that were successfully sent
       
  1284     // or received
       
  1285 
       
  1286     // Rescedule failed entries
       
  1287     // We have a member that tells which command to use
       
  1288     // (Send or receive)
       
  1289 
       
  1290     // The central repository file contains a list of hopeless cases.
       
  1291     // These are not rescheduled
       
  1292 
       
  1293     TMsvSchedulePackage* schedulePackage = new( ELeave ) TMsvSchedulePackage;
       
  1294     CleanupStack::PushL( schedulePackage );
       
  1295     PopulateSchedulePackage( iParameter, ETrue, *schedulePackage );
       
  1296 
       
  1297     // Failed forward entries
       
  1298     if( iForwardOperation && iForwardOperation->Failed().Count() > 0 )
       
  1299         {
       
  1300         HandleFailedForwardsL( *schedulePackage );
       
  1301         }
       
  1302 
       
  1303     // Successfully sent entries
       
  1304     if( iSendOperation && iSendOperation->Sent().Count() > 0 )
       
  1305         {
       
  1306         HandleSuccessfulSendsL();
       
  1307         }
       
  1308 
       
  1309     // Entries that failed to be sent
       
  1310     if ( iSendOperation && iSendOperation->Failed().Count() > 0 )
       
  1311         {
       
  1312         HandleFailedSendsL( *schedulePackage );
       
  1313         }
       
  1314 
       
  1315     // Message generation (branding messages)
       
  1316     if ( iReceiveMessage && iCurrentCommand == EMmsMessageGeneration )
       
  1317         {
       
  1318         CleanupAfterMessageGenerationL();
       
  1319         }
       
  1320 
       
  1321     // Mark entries that failed to be fetched
       
  1322     // If there is some error connected to this, it must be returned to caller
       
  1323     // as fetching is automatic.
       
  1324     TBool restartFetch = EFalse;
       
  1325     if ( iReceiveMessage && iReceiveMessage->Failed().Count() > 0 )
       
  1326         {
       
  1327         restartFetch = HandleFailedReceivesL( *schedulePackage, fatalError );
       
  1328         }
       
  1329 
       
  1330     // Successfully received entries
       
  1331     if ( iReceiveMessage && iReceiveMessage->Received().Count() > 0 )
       
  1332         {
       
  1333         HandleSuccessfulReceivesL();
       
  1334         }
       
  1335 
       
  1336     // Remove bad notifications from task scheduler
       
  1337     if ( iReceiveMessage && iReceiveMessage->BadNotifications().Count() > 0 )
       
  1338         {
       
  1339         HandleBadNotificationsL();
       
  1340         }
       
  1341         
       
  1342     if ( restartFetch )
       
  1343         {
       
  1344         // We did find some failed notifications that were in inbox or MMBox folder
       
  1345         // These are not normally rescheduled
       
  1346         // But if the error was due to lack of disk space and we have been able to
       
  1347         // free the disk space by deleting some older messages belonging to a 
       
  1348         // lazy application, we can retry the fetch immediately
       
  1349         
       
  1350         // We must clear the receiver class to start with a clean slate.
       
  1351         delete iReceiveMessage;
       
  1352         iReceiveMessage = NULL;
       
  1353         FetchFromMmscL();
       
  1354         iError = KMmsErrorApplicationDiskFull;
       
  1355         }
       
  1356 
       
  1357     // update delivery status counts and reschedule possible extra delivcery reports
       
  1358     if ( iCommand == EMmsLogDeliveryReport )
       
  1359         {
       
  1360         UpdateDeliveryReportsL( *schedulePackage );
       
  1361         }
       
  1362      
       
  1363     // handle failed read report entries    
       
  1364     if ( iReadReport && iReadReport->Failed().Count() > 0 )
       
  1365         {
       
  1366         HandleFailedReadReports();
       
  1367         }
       
  1368         
       
  1369     CleanupStack::PopAndDestroy( schedulePackage );
       
  1370 
       
  1371 #ifndef _NO_MMSS_LOGGING_
       
  1372     TMmsLogger::Log( _L("UpdateEntriesL done, error: %d" ), iError );
       
  1373 #endif
       
  1374     if ( fatalError != KErrNone )
       
  1375         {
       
  1376 #ifndef _NO_MMSS_LOGGING_
       
  1377         TMmsLogger::Log( _L("UpdateEntriesL, fatal error: %d" ), fatalError );
       
  1378 #endif
       
  1379         // we catch this
       
  1380         User::Leave( fatalError );
       
  1381         // return not needed as User::Leave returns
       
  1382         }
       
  1383     }
       
  1384     
       
  1385 // ---------------------------------------------------------
       
  1386 // 
       
  1387 // ---------------------------------------------------------
       
  1388 //
       
  1389 void CMmsServerMtm::HandleFailedForwardsL( TMsvSchedulePackage& aPackage )
       
  1390     {
       
  1391     TInt count = 0;
       
  1392     TMsvEntry entry;
       
  1393     TInt error = KErrNone;
       
  1394 
       
  1395     count = iForwardOperation->Failed().Count();
       
  1396 #ifndef _NO_MMSS_LOGGING_
       
  1397     TMmsLogger::Log( _L("- %d failed (not sent) forward entries"), count );
       
  1398     TInt rescheduled = count; // rescheduled needed only for logging
       
  1399 #endif
       
  1400     // Loop selection and make them reschedulable (readonly == false)
       
  1401     while ( count-- )
       
  1402         {
       
  1403         if ( iServerEntry->SetEntry( iForwardOperation->Failed().At( count ) ) == KErrNone )
       
  1404             {
       
  1405             entry = iServerEntry->Entry();
       
  1406             entry.SetReadOnly( EFalse );
       
  1407             iServerEntry->ChangeEntry( entry ); // ignore error
       
  1408             }
       
  1409         }
       
  1410 
       
  1411     //
       
  1412     //  Now reschedule.
       
  1413     //
       
  1414     iScheduleSend->ReScheduleL( iForwardOperation->Failed(), aPackage );
       
  1415 
       
  1416     // Mark entries that failed to be rescheduled
       
  1417     count = iForwardOperation->Failed().Count();
       
  1418     while ( count-- )
       
  1419         {
       
  1420         if ( iServerEntry->SetEntry( iForwardOperation->Failed().At( count ) ) == KErrNone )
       
  1421             {
       
  1422             entry = iServerEntry->Entry();
       
  1423             if ( entry.SendingState() != KMsvSendStateResend )
       
  1424                 {
       
  1425 #ifndef _NO_MMSS_LOGGING_
       
  1426                 TMmsLogger::Log( _L("- forward entry failed to reschedule, setting state to failed") );
       
  1427 #endif
       
  1428                 entry.SetSendingState( KMsvSendStateFailed );
       
  1429                 error = iServerEntry->ChangeEntry( entry ); // ignore error
       
  1430 #ifndef _NO_MMSS_LOGGING_
       
  1431                 if( error != KErrNone )
       
  1432                     {
       
  1433                     TMmsLogger::Log( _L("- ERROR: changing entry failed") );
       
  1434                     }
       
  1435 #endif
       
  1436                 // Clear related notification from Inbox:
       
  1437                 // Get the related notification id
       
  1438                 CMsvStore* store = NULL;
       
  1439                 store = iServerEntry->EditStoreL();
       
  1440                 CleanupStack::PushL( store ); // ***
       
  1441                 iMmsHeaders->RestoreL( *store );
       
  1442                 CleanupStack::PopAndDestroy( store );
       
  1443                 TMsvId relatedEntryId = iMmsHeaders->RelatedEntry();
       
  1444                 iMmsHeaders->Reset(); // headers not needed any more
       
  1445 
       
  1446                 if( relatedEntryId != KMsvNullIndexEntryId )
       
  1447                     {
       
  1448 #ifndef _NO_MMSS_LOGGING_
       
  1449                     TMmsLogger::Log( _L("- related notification-entry exists, clearing it") );
       
  1450 #endif
       
  1451                     // Set context (iServerEntry and entry) to notification and clear it
       
  1452                     error = iServerEntry->SetEntry( relatedEntryId );
       
  1453 #ifndef _NO_MMSS_LOGGING_
       
  1454                     if( error != KErrNone )
       
  1455                         {
       
  1456                         TMmsLogger::Log( _L("- ERROR: Could not set entry") );
       
  1457                         }
       
  1458 #endif
       
  1459                     entry = iServerEntry->Entry();
       
  1460                     entry.iMtmData2 &= ~KMmsNewOperationForbidden; // not forbidden
       
  1461                     entry.iMtmData2 &= ~KMmsOperationOngoing;      // not ongoing
       
  1462                     entry.iMtmData2 |= KMmsOperationFinished;      // finished
       
  1463                     entry.iMtmData2 |= KMmsOperationResult;        // NOK
       
  1464                     entry.SetReadOnly( ETrue );
       
  1465                     error = iServerEntry->ChangeEntry( entry );
       
  1466 #ifndef _NO_MMSS_LOGGING_
       
  1467                     if( error != KErrNone )
       
  1468                         {
       
  1469                         TMmsLogger::Log( _L("- ERROR: Could not change related entry") );
       
  1470                         }
       
  1471                     TMmsLogger::Log( _L("- Clear the related-entry link itself") );
       
  1472 #endif
       
  1473 
       
  1474                     // Clear related-id link from forward entry
       
  1475                     if ( iMsvSelection->Count() > count )
       
  1476                         {
       
  1477                         error = iServerEntry->SetEntry( iMsvSelection->At( count ) );
       
  1478                         }
       
  1479                     else
       
  1480                         {
       
  1481                         // We should never get this,
       
  1482                         // we check count only to keep CodeScanner happy
       
  1483                         error = KErrNotFound; 
       
  1484                         }
       
  1485                     if ( error == KErrNone )
       
  1486                         {
       
  1487                         store = iServerEntry->EditStoreL();
       
  1488                         CleanupStack::PushL( store ); // ***
       
  1489                         iMmsHeaders->RestoreL( *store );
       
  1490                         iMmsHeaders->SetRelatedEntry( KMsvNullIndexEntryId );
       
  1491                         iMmsHeaders->StoreL( *store );
       
  1492                         store->CommitL();
       
  1493                         CleanupStack::PopAndDestroy( store );
       
  1494                         iMmsHeaders->Reset(); // headers not needed any more
       
  1495 #ifndef _NO_MMSS_LOGGING_
       
  1496                         TMmsLogger::Log( _L("- Related-entry and the link cleared") );
       
  1497 #endif
       
  1498                         }
       
  1499                     }
       
  1500 
       
  1501                 // let go of the entry
       
  1502                 iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  1503                 }
       
  1504             else
       
  1505                 {
       
  1506                 //
       
  1507                 // Delete successfully rescheduled entries
       
  1508                 //
       
  1509 #ifndef _NO_MMSS_LOGGING_
       
  1510                 TMmsLogger::Log( _L("- notification is in resend, as it should") );
       
  1511 #endif
       
  1512                 iForwardOperation->Failed().Delete( count );
       
  1513                 }
       
  1514             }
       
  1515 #ifndef _NO_MMSS_LOGGING_
       
  1516         else
       
  1517             {
       
  1518             TMmsLogger::Log( _L("- ERROR: could not access entry %d"), count );
       
  1519             }
       
  1520 #endif
       
  1521         }
       
  1522 
       
  1523 #ifndef _NO_MMSS_LOGGING_
       
  1524     count = iForwardOperation->Failed().Count();
       
  1525     rescheduled = rescheduled - count;
       
  1526     if ( rescheduled > 0 )
       
  1527         {
       
  1528         TMmsLogger::Log( _L("- %d rescheduled forward entries"), rescheduled );
       
  1529         }
       
  1530     if ( count > 0 )
       
  1531         {
       
  1532         TMmsLogger::Log( _L("- %d not rescheduled forward entries"), count );
       
  1533         }
       
  1534 #endif
       
  1535     }
       
  1536     
       
  1537 // ---------------------------------------------------------
       
  1538 // 
       
  1539 // ---------------------------------------------------------
       
  1540 //
       
  1541 void CMmsServerMtm::HandleSuccessfulSendsL()
       
  1542     {
       
  1543     TInt count = 0;
       
  1544     TMsvEntry entry;
       
  1545     
       
  1546     // Delete schedule should not be needed in the case of successfully
       
  1547     // sent entries.
       
  1548     count = iSendOperation->Sent().Count();
       
  1549 #ifndef _NO_MMSS_LOGGING_
       
  1550     TMmsLogger::Log( _L("- %d Sent entries"), count );
       
  1551 #endif
       
  1552     iScheduleSend->DeleteScheduleL( iSendOperation->Sent() );
       
  1553     while ( count-- )
       
  1554         {
       
  1555         if ( iServerEntry->SetEntry( iSendOperation->Sent().At( count ) ) == KErrNone )
       
  1556             {
       
  1557             entry = iServerEntry->Entry();
       
  1558             entry.SetSendingState( KMsvSendStateSent );
       
  1559             if ( entry.Parent() == KMsvSentEntryIdValue )
       
  1560                 {
       
  1561                 // if we have not managed to move this entry away from outbox,
       
  1562                 // it must not be set to read only state
       
  1563                 entry.SetReadOnly( ETrue );
       
  1564                 }
       
  1565             // We don't want to leave here, we want to continue.
       
  1566             // The next message may succeed.
       
  1567             // We don't consider this fatal: If the message
       
  1568             // has been successfully sent, it should already
       
  1569             // be moved to sent folder.
       
  1570             // If the user tries to send messages during backup/restore,
       
  1571             // it is his own fault if the messages are sent more than once.
       
  1572             iServerEntry->ChangeEntry( entry );
       
  1573             }
       
  1574         }
       
  1575     }
       
  1576 
       
  1577 // ---------------------------------------------------------
       
  1578 // 
       
  1579 // ---------------------------------------------------------
       
  1580 //
       
  1581 void CMmsServerMtm::HandleFailedSendsL( TMsvSchedulePackage& aPackage )
       
  1582     {
       
  1583     TInt count = 0;
       
  1584     TMsvEntry entry;
       
  1585     
       
  1586     count = iSendOperation->Failed().Count();
       
  1587 #ifndef _NO_MMSS_LOGGING_
       
  1588     TInt rescheduled = count;
       
  1589     TMmsLogger::Log( _L("- %d failed (not sent) entries"), count );
       
  1590 #endif
       
  1591     while ( count-- )
       
  1592         {
       
  1593         if ( iServerEntry->SetEntry( iSendOperation->Failed().At( count ) ) == KErrNone )
       
  1594             {
       
  1595             entry = iServerEntry->Entry();
       
  1596             // we set the entry into failed state after we have
       
  1597             // checked if it still can be rescheduled.
       
  1598             entry.SetReadOnly( EFalse );
       
  1599             iServerEntry->ChangeEntry( entry ); // ignore error
       
  1600             if ( entry.SendingState() == KMsvSendStateSuspended &&
       
  1601                 entry.iError != KMmsErrorOfflineMode )
       
  1602                 {
       
  1603                 // suspended by user, not offline mode
       
  1604                 // We remove this just in case.
       
  1605                 // If everything has gone well, the error is "KErrNotFound"
       
  1606                 // and the entry would not be rescheduled, but this is an
       
  1607                 // extra precaution.
       
  1608                 iSendOperation->Failed().Delete( count );    
       
  1609                 }
       
  1610             }
       
  1611         }
       
  1612         
       
  1613     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  1614     count = iSendOperation->Failed().Count();
       
  1615 
       
  1616     if ( count > 0 )
       
  1617         {
       
  1618         // Check needed to avoid a stupid ASSERT_DEBUG
       
  1619         iScheduleSend->ReScheduleL( iSendOperation->Failed(), aPackage );
       
  1620         }
       
  1621 
       
  1622     // Mark entries that failed to be rescheduled
       
  1623     count = iSendOperation->Failed().Count();
       
  1624 
       
  1625     while ( count-- )
       
  1626         {
       
  1627         if ( iServerEntry->SetEntry( iSendOperation->Failed().At( count ) ) == KErrNone )
       
  1628             {
       
  1629             entry = iServerEntry->Entry();
       
  1630             if ( entry.SendingState() != KMsvSendStateResend )
       
  1631                 {
       
  1632 #ifndef _NO_MMSS_LOGGING_
       
  1633                 TMmsLogger::Log( _L("- setting state to failed") );
       
  1634 #endif
       
  1635                 entry.SetSendingState( KMsvSendStateFailed );
       
  1636                 iServerEntry->ChangeEntry( entry ); // ignore error
       
  1637                 // let go of the entry
       
  1638                 iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  1639                 }
       
  1640             else
       
  1641                 {
       
  1642                 iSendOperation->Failed().Delete( count );
       
  1643                 }
       
  1644             }
       
  1645 #ifndef _NO_MMSS_LOGGING_
       
  1646         else
       
  1647             {
       
  1648             TMmsLogger::Log( _L("- could not access entry %d"), count );
       
  1649             }
       
  1650 #endif
       
  1651         }
       
  1652 
       
  1653     count = iSendOperation->Failed().Count();
       
  1654 #ifndef _NO_MMSS_LOGGING_
       
  1655     rescheduled = rescheduled - count;
       
  1656     if ( rescheduled > 0 )
       
  1657         {
       
  1658         TMmsLogger::Log( _L("- %d rescheduled for sending"), rescheduled );
       
  1659         }
       
  1660     if ( count > 0 )
       
  1661         {
       
  1662         TMmsLogger::Log( _L("- %d hopeless, not rescheduled for sending"), count );
       
  1663         }
       
  1664 #endif
       
  1665 
       
  1666     }
       
  1667     
       
  1668 // ---------------------------------------------------------
       
  1669 // 
       
  1670 // ---------------------------------------------------------
       
  1671 //
       
  1672 void CMmsServerMtm::CleanupAfterMessageGenerationL()
       
  1673     {
       
  1674 #ifndef _NO_MMSS_LOGGING_
       
  1675     TMmsLogger::Log( _L("- Finished message generation") );
       
  1676 #endif
       
  1677     // we try only once.
       
  1678     // The whole selection must be in the same place.
       
  1679     CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
       
  1680     CleanupStack::PushL( selection );
       
  1681     
       
  1682     // everything must go.
       
  1683     if ( iReceiveMessage->BadNotifications().Count() > 0 )
       
  1684         {
       
  1685         selection->AppendL( iReceiveMessage->BadNotifications().Back( 0 ),
       
  1686             iReceiveMessage->BadNotifications().Count() );
       
  1687         iReceiveMessage->BadNotifications().Reset();
       
  1688         }
       
  1689     
       
  1690     if ( iReceiveMessage->Failed().Count() > 0 )
       
  1691         {
       
  1692         selection->AppendL( iReceiveMessage->Failed().Back( 0 ),
       
  1693             iReceiveMessage->Failed().Count() );
       
  1694         iReceiveMessage->Failed().Reset();
       
  1695         }
       
  1696         
       
  1697     if ( iReceiveMessage->Received().Count() > 0 )
       
  1698         {
       
  1699         selection->AppendL( iReceiveMessage->Received().Back( 0 ),
       
  1700             iReceiveMessage->Received().Count() );
       
  1701         iReceiveMessage->Received().Reset();
       
  1702         }
       
  1703     
       
  1704     // If the next loop fails, we don't care:
       
  1705     // The files will be deleted ayway, and the notifications will be orphaned
       
  1706     // If there is something weird going on during the boot,
       
  1707     // the phone won't probably work after this anyway.
       
  1708     if ( selection->Count() > 0 )
       
  1709         {
       
  1710         if ( iServerEntry->SetEntry( selection->At( 0 ) ) == KErrNone )
       
  1711             {
       
  1712             if ( iServerEntry->SetEntry( iServerEntry->Entry().Parent() ) == KErrNone )
       
  1713                 {
       
  1714                 iServerEntry->DeleteEntries( *selection );
       
  1715                 }
       
  1716             }
       
  1717         iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  1718         }
       
  1719     CleanupStack::PopAndDestroy( selection );
       
  1720 
       
  1721     // Then we delete the files in the directory
       
  1722     // (if anything left)
       
  1723     CFileMan* fileMan = CFileMan::NewL( iFs );
       
  1724     CleanupStack::PushL( fileMan );
       
  1725     // Best effort - ignore error
       
  1726     fileMan->RmDir( KMmsMessageVariationDirectory );
       
  1727     CleanupStack::PopAndDestroy( fileMan );
       
  1728     
       
  1729     }
       
  1730     
       
  1731 // ---------------------------------------------------------
       
  1732 // 
       
  1733 // ---------------------------------------------------------
       
  1734 //
       
  1735 TBool CMmsServerMtm::HandleFailedReceivesL( TMsvSchedulePackage& aPackage, TInt& aFatalError )
       
  1736     {
       
  1737     TInt count = 0;
       
  1738     TMsvEntry entry;
       
  1739     TInt error = KErrNone;
       
  1740     TBool restartFetch = EFalse;
       
  1741     
       
  1742     iMsvSelection->Reset();
       
  1743     count = iReceiveMessage->Failed().Count();
       
  1744 #ifndef _NO_MMSS_LOGGING_
       
  1745     TMmsLogger::Log( _L("- %d failed (not received) entries"), count );
       
  1746 #endif
       
  1747     // Check if the current receive mode is manual
       
  1748     TBool manual = EFalse;
       
  1749     if( iReceiveMessage->InForeignNetwork() )
       
  1750         {
       
  1751         if( iMmsSettings->ReceivingModeForeign() == EMmsReceivingManual )
       
  1752             {
       
  1753             manual = ETrue;
       
  1754             }
       
  1755         }
       
  1756     else
       
  1757         {
       
  1758         if( iMmsSettings->ReceivingModeHome() == EMmsReceivingManual )
       
  1759             {
       
  1760             manual = ETrue;
       
  1761             }
       
  1762         }
       
  1763 
       
  1764     TBool inInbox = EFalse;
       
  1765     TBool inMmsFolder = EFalse;
       
  1766     TBool inMmboxFolder = EFalse;
       
  1767 
       
  1768     while ( count-- )
       
  1769         {
       
  1770         error = iServerEntry->SetEntry( iReceiveMessage->Failed().At( count ) );
       
  1771         if ( error == KErrNone )
       
  1772             {
       
  1773             entry = iServerEntry->Entry();
       
  1774 
       
  1775             if ( entry.iMtmData2 & KMmsDoNotMoveToInbox )
       
  1776                 {
       
  1777 #ifndef _NO_MMSS_LOGGING_
       
  1778                 TMmsLogger::Log( _L("- do not move entry to inbox "));
       
  1779 #endif
       
  1780                 // We do not reschedule this. It will potentially cause problems at mode change
       
  1781                 // if it has not been handled by then.
       
  1782                 iReceiveMessage->Failed().Delete( count );
       
  1783                 // it is put into bad list and deleted later
       
  1784                 iReceiveMessage->BadNotifications().AppendL( entry.Id() );
       
  1785                 }
       
  1786             else
       
  1787                 {
       
  1788                 if ( entry.Parent() == FindMMSFolderL() )
       
  1789                     {
       
  1790                     inMmsFolder = ETrue;
       
  1791                     }
       
  1792                 else if ( entry.Parent() == KMsvGlobalInBoxIndexEntryIdValue )        
       
  1793                     {
       
  1794                     inInbox = ETrue;
       
  1795                     // inbox entries will not be rescheduled
       
  1796                     if ( entry.iError == KMmsErrorApplicationDiskFull )
       
  1797                         {
       
  1798                         // This is best effort only - error ignored
       
  1799                         iMsvSelection->AppendL( iReceiveMessage->Failed().At( count ) );
       
  1800                         restartFetch = ETrue;
       
  1801                         }
       
  1802                     iReceiveMessage->Failed().Delete( count );
       
  1803                     }
       
  1804                 else
       
  1805                     {
       
  1806                     inMmboxFolder = ETrue;
       
  1807                     if ( entry.iError == KMmsErrorApplicationDiskFull )
       
  1808                         {
       
  1809                         // This is best effort only - error ignored
       
  1810                         iMsvSelection->AppendL( iReceiveMessage->Failed().At( count ) );
       
  1811                         restartFetch = ETrue;
       
  1812                         }
       
  1813                     // mmbox entries will not be rescheduled
       
  1814                     iReceiveMessage->Failed().Delete( count );
       
  1815                     manual = EFalse; // manual mode must not affect the mmbox notification
       
  1816                     }
       
  1817                 // We don't have a separate receiving state.
       
  1818                 // We just use sending state instead.
       
  1819                 // We are the only one that uses scheduled receiving.
       
  1820 #ifndef _NO_MMSS_LOGGING_
       
  1821                 TMmsLogger::Log( _L("- marking sending state as failed "));
       
  1822 #endif
       
  1823                 entry.SetSendingState( KMsvSendStateFailed );
       
  1824 
       
  1825                 if ( manual && inMmsFolder )
       
  1826                     {
       
  1827                     // Change the iMtm from KUidMsgTypeMultimedia to 
       
  1828                     // KUidMsgMMSNotification   
       
  1829                     entry.iMtm.iUid = KUidMsgMMSNotification.iUid; // this is a notification
       
  1830 
       
  1831                     entry.iMtmData2 &= ~KMmsOperationFinished; // clear flag just in case
       
  1832                     entry.iMtmData2 &= ~KMmsOperationResult; // clear flag just in case
       
  1833                     entry.iMtmData2 &= ~KMmsOperationOngoing; // Fetch operation is not active anymore
       
  1834                     entry.iMtmData2 &= ~KMmsNewOperationForbidden; // New operation can be started
       
  1835                     entry.iMtmData1 |= KMmsMessageMobileTerminated;
       
  1836                     entry.SetReadOnly( ETrue );
       
  1837                     entry.iError = KErrNone;
       
  1838                     entry.SetSendingState( KMsvSendStateUnknown );                    
       
  1839                     }
       
  1840                 else if ( inInbox  )
       
  1841                     {
       
  1842                     // Mark original notification
       
  1843                     CMmsBaseOperation::MarkNotificationOperationFailed( entry ); 
       
  1844                     if ( entry.iError != KMmsErrorApplicationDiskFull )
       
  1845                         {
       
  1846                         entry.SetReadOnly( ETrue );
       
  1847                         }
       
  1848                     }
       
  1849                 else if ( inMmboxFolder )
       
  1850                     {
       
  1851 #ifndef _NO_MMSS_LOGGING_
       
  1852                     TMmsLogger::Log( _L("- in mmbox folder"));
       
  1853 #endif
       
  1854                     TRAP( error, CMmsBaseOperation::MarkDuplicateL(
       
  1855                         CMmsBaseOperation::EMmsNotificationOperationFailed,
       
  1856                         *iServerEntry ) );
       
  1857                     error = KErrNone; // ignore error from trap    
       
  1858                     entry = iServerEntry->Entry();
       
  1859                     CMmsBaseOperation::MarkNotificationOperationFailed( entry );
       
  1860                     if ( entry.iError != KMmsErrorApplicationDiskFull )
       
  1861                         {
       
  1862                         entry.SetReadOnly( ETrue );
       
  1863                         }
       
  1864 #ifndef _NO_MMSS_LOGGING_
       
  1865                     TMmsLogger::Log( _L("- marking original notif failed"));
       
  1866 #endif                    
       
  1867                     }
       
  1868                 else
       
  1869                     {
       
  1870                     // keep LINT happy
       
  1871                     }
       
  1872                 error = iServerEntry->ChangeEntry( entry );
       
  1873                 
       
  1874                 // move the entry from mms folder to the inbox in manual mode.
       
  1875                 if ( manual && inMmsFolder )
       
  1876                     {
       
  1877                     iError = iServerEntry->SetEntry( entry.Parent() );
       
  1878                     if ( iError == KErrNone )
       
  1879                         {
       
  1880                         error = iServerEntry->MoveEntryWithinService(
       
  1881                             entry.Id(), KMsvGlobalInBoxIndexEntryIdValue );
       
  1882                         }
       
  1883                     else
       
  1884                         {
       
  1885                         error = iError;
       
  1886                         }
       
  1887                     if ( error == KErrNone )
       
  1888                         {
       
  1889                         inInbox = ETrue;
       
  1890                         // This should not be rescheduled as it has moved to inbox
       
  1891                         iReceiveMessage->Failed().Delete( count );
       
  1892                         }
       
  1893                     }
       
  1894                 }
       
  1895             if ( aFatalError == KErrNone )
       
  1896                 {
       
  1897                 // if we canot access the entry, tell the caller
       
  1898                 aFatalError = error;
       
  1899                 }
       
  1900             // let go of the entry
       
  1901             iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  1902 #ifndef _NO_MMSS_LOGGING_
       
  1903             TMmsLogger::Log( _L("UpdateEntriesL: entry #%d, sending state = failed"), count );
       
  1904             TMmsLogger::Log( _L("UpdateEntriesL: entry #%d, error = %d"), count, entry.iError );
       
  1905             if ( error != KErrNone )
       
  1906                 {
       
  1907                 TMmsLogger::Log( _L("UpdateEntriesL: ChangeEntry failed, error %d"), error );
       
  1908                 }
       
  1909 #endif
       
  1910             }
       
  1911 #ifndef _NO_MMSS_LOGGING_
       
  1912         else
       
  1913             {
       
  1914             // Not found is not fatal. What is gone is gone.
       
  1915             if ( error != KErrNotFound )
       
  1916                 {
       
  1917                 if ( aFatalError == KErrNone )
       
  1918                     {
       
  1919                     aFatalError = error;
       
  1920                     }
       
  1921                 }
       
  1922             TMmsLogger::Log( _L("UpdateEntriesL: could not access entry #%d"), count );
       
  1923             }
       
  1924 #endif
       
  1925         }
       
  1926 
       
  1927     // only if the notification is in mmsfolder, reschedule the notification
       
  1928     // if the notification is in Inbox or in mmbox folder, do not rescedule.
       
  1929     // We have removed each notification from failed list if it was originally
       
  1930     // in inbox or in MMBox folder or if it was successfully moved to inbox
       
  1931     if( iReceiveMessage->Failed().Count() > 0 )
       
  1932         {
       
  1933         iScheduleSend->ReScheduleL( iReceiveMessage->Failed(), aPackage );
       
  1934         }
       
  1935     // The messages that could not be rescheduled anymore, are either deleted, or moved
       
  1936     // to Inbox to be handled manually
       
  1937     count = iReceiveMessage->Failed().Count();
       
  1938     // we do not delete hopeless entries:
       
  1939     // There is a separate error watcher that decides
       
  1940     // what to do with them.
       
  1941     // For example: If there is no access point, receiving
       
  1942     // fails. The error watcher gives notice to user, and
       
  1943     // when the user has entered the access point, the 
       
  1944     // fetch is restarted by the error watcher.
       
  1945 #ifndef _NO_MMSS_LOGGING_
       
  1946     TInt hopeless = count;
       
  1947 #endif
       
  1948     while ( count-- )
       
  1949         {
       
  1950         TMsvId failedEntry = iReceiveMessage->Failed().At( count );
       
  1951         if ( iServerEntry->SetEntry( failedEntry ) == KErrNone )
       
  1952             {
       
  1953             entry = iServerEntry->Entry();
       
  1954             // update retry count
       
  1955             TRAP( error, 
       
  1956                 {
       
  1957                 CMsvStore* store = NULL;
       
  1958                 store = iServerEntry->ReadStoreL();
       
  1959                 CleanupStack::PushL( store );
       
  1960                 CMmsScheduledEntry* mmsScheduledEntry =
       
  1961                     CMmsScheduledEntry::NewL( iServerEntry->Entry() );
       
  1962                 CleanupStack::PushL( mmsScheduledEntry );
       
  1963                 mmsScheduledEntry->RestoreL( *store );
       
  1964                 entry.iMtmData3 &= ~KMmsRetryCountMask;
       
  1965                 entry.iMtmData3 |= mmsScheduledEntry->MmsRecipient().Retries();
       
  1966                 iServerEntry->ChangeEntry( entry );
       
  1967                 CleanupStack::PopAndDestroy( mmsScheduledEntry );
       
  1968                 CleanupStack::PopAndDestroy( store );
       
  1969                 }
       
  1970             );
       
  1971 
       
  1972             if ( entry.SendingState() == KMsvSendStateFailed ) 
       
  1973                 {
       
  1974                 // remove from list just to see what was left over
       
  1975                 iReceiveMessage->Failed().Delete( count );
       
  1976                 }
       
  1977             }
       
  1978         }
       
  1979 #ifndef _NO_MMSS_LOGGING_
       
  1980     count = iReceiveMessage->Failed().Count();
       
  1981     hopeless = hopeless - count;
       
  1982     if ( count > 0 )
       
  1983         {
       
  1984         TMmsLogger::Log( _L("- %d rescheduled for receiving"), count );
       
  1985         }
       
  1986     if ( hopeless > 0 )
       
  1987         {
       
  1988         TMmsLogger::Log( _L("- %d hopeless, not rescheduled for receiving"), hopeless );
       
  1989         }
       
  1990 #endif  
       
  1991         
       
  1992     return restartFetch;
       
  1993     }
       
  1994     
       
  1995 // ---------------------------------------------------------
       
  1996 // 
       
  1997 // ---------------------------------------------------------
       
  1998 //
       
  1999 void CMmsServerMtm::HandleSuccessfulReceivesL()
       
  2000     {
       
  2001 #ifndef _NO_MMSS_LOGGING_
       
  2002     TMmsLogger::Log( _L("- %d received entries"), iReceiveMessage->Received().Count() );
       
  2003 #endif
       
  2004     TMsvId parent = KMsvNullIndexEntryId;
       
  2005     // The whole selection must be in the same place.
       
  2006     if ( iServerEntry->SetEntry( iReceiveMessage->Received().At( 0 ) ) == KErrNone  )
       
  2007         {
       
  2008         parent = iServerEntry->Entry().Parent();
       
  2009         }
       
  2010 
       
  2011     CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
       
  2012     CleanupStack::PushL( selection );
       
  2013     selection->AppendL( iReceiveMessage->Received().Back( 0 ),
       
  2014         iReceiveMessage->Received().Count() );
       
  2015 
       
  2016     // if entry is in inbox or in MMBoxfolder,
       
  2017     // check possible duplicate and mark it "fetched from server"
       
  2018     if ( parent == KMsvGlobalInBoxIndexEntryIdValue || parent == iMmsSettings->MMBoxFolder() )
       
  2019         {
       
  2020         for ( TInt i = selection->Count(); i > 0; i-- )
       
  2021             {
       
  2022             if ( iServerEntry->SetEntry( selection->At( i - 1 )) == KErrNone )
       
  2023                 {
       
  2024 #ifndef _NO_MMSS_LOGGING_
       
  2025                 TMmsLogger::Log( _L("- check possible duplicate" ));
       
  2026 #endif
       
  2027                 CMsvStore* store = iServerEntry->ReadStoreL();
       
  2028                 CleanupStack::PushL( store );
       
  2029                 iMmsHeaders->RestoreL( *store );
       
  2030                 CleanupStack::PopAndDestroy( store );
       
  2031                 store = NULL;
       
  2032                 TMsvId duplicate = KMsvNullIndexEntryId;
       
  2033 
       
  2034                 if ( parent == KMsvGlobalInBoxIndexEntryIdValue )
       
  2035                     {
       
  2036                     TMsvId mmboxFolder = iMmsSettings->MMBoxFolder();
       
  2037                     if ( mmboxFolder != KMsvNullIndexEntryId )
       
  2038                         {
       
  2039                         FindDuplicateNotificationL( mmboxFolder, *iMmsHeaders, duplicate );
       
  2040                         }
       
  2041                     }
       
  2042                 else // parent is mmbox folder
       
  2043                     {
       
  2044                     duplicate = iMmsHeaders->RelatedEntry();
       
  2045                     }
       
  2046                 if ( duplicate != KMsvNullIndexEntryId )
       
  2047                     {
       
  2048 #ifndef _NO_MMSS_LOGGING_
       
  2049                     TMmsLogger::Log( _L("- duplicate found"));
       
  2050 #endif
       
  2051                     if ( iServerEntry->SetEntry( duplicate ) == KErrNone )
       
  2052                         {
       
  2053                         // Mark duplicate
       
  2054                         TMsvEntry dupEntry = iServerEntry->Entry();
       
  2055                         CMmsBaseOperation::MarkNotificationDeletedFromMmbox( dupEntry );
       
  2056                         iServerEntry->ChangeEntry( dupEntry );
       
  2057 #ifndef _NO_MMSS_LOGGING_
       
  2058                         TMmsLogger::Log( _L("- duplicate marked as fetched from mmbox"));
       
  2059 #endif
       
  2060                         }
       
  2061                     } 
       
  2062                 }
       
  2063             }
       
  2064         }
       
  2065     if ( parent != KMsvNullIndexEntryId && iServerEntry->SetEntry( parent ) == KErrNone )
       
  2066         {
       
  2067         iServerEntry->DeleteEntries( *selection );
       
  2068         }
       
  2069     CleanupStack::PopAndDestroy( selection );
       
  2070     }
       
  2071     
       
  2072 // ---------------------------------------------------------
       
  2073 // 
       
  2074 // ---------------------------------------------------------
       
  2075 //
       
  2076 void CMmsServerMtm::HandleBadNotificationsL()
       
  2077     {
       
  2078 #ifndef _NO_MMSS_LOGGING_
       
  2079     TMmsLogger::Log( _L("- %d bad notification entries"), iReceiveMessage->BadNotifications().Count() );
       
  2080 #endif
       
  2081     // The whole selection must be in the same place.
       
  2082     if ( iServerEntry->SetEntry( iReceiveMessage->BadNotifications().At( 0 ) ) == KErrNone )
       
  2083         {
       
  2084         if ( iServerEntry->SetEntry( iServerEntry->Entry().Parent() ) == KErrNone )
       
  2085             {
       
  2086             CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
       
  2087             CleanupStack::PushL( selection );
       
  2088             selection->AppendL( iReceiveMessage->BadNotifications().Back( 0 ),
       
  2089                 iReceiveMessage->BadNotifications().Count() );
       
  2090             iServerEntry->DeleteEntries( *selection );
       
  2091             CleanupStack::PopAndDestroy( selection );
       
  2092             }
       
  2093         }
       
  2094     }
       
  2095     
       
  2096 // ---------------------------------------------------------
       
  2097 // 
       
  2098 // ---------------------------------------------------------
       
  2099 //
       
  2100 void CMmsServerMtm::UpdateDeliveryReportsL( TMsvSchedulePackage& aPackage )
       
  2101     {
       
  2102     TInt error = KErrNone;
       
  2103     TMsvEntry entry;
       
  2104 
       
  2105 #ifndef _NO_MMSS_LOGGING_
       
  2106     TMmsLogger::Log( _L("- logged delivery report" ));
       
  2107 #endif
       
  2108     if ( iError == KErrNone )
       
  2109         {
       
  2110         // first entry in selection was handled
       
  2111         CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
       
  2112         CleanupStack::PushL( selection );
       
  2113         selection->AppendL( iMsvSelection->At( 0 ), 1 );
       
  2114         if ( selection->Count() > 0 )
       
  2115             {
       
  2116             error = iServerEntry->SetEntry( selection->At( 0 ) );
       
  2117             }
       
  2118         else
       
  2119             {
       
  2120             // this will never happen - we are just keeping codescanner happy
       
  2121             error = KErrNotFound;
       
  2122             }
       
  2123         if ( error == KErrNone )
       
  2124             {
       
  2125             if ( iServerEntry->SetEntry( iServerEntry->Entry().Parent() ) == KErrNone )
       
  2126                 {
       
  2127                 iServerEntry->DeleteEntries( *selection );
       
  2128                 }
       
  2129             }
       
  2130         CleanupStack::PopAndDestroy( selection );
       
  2131         iMsvSelection->Delete( 0 );
       
  2132         }
       
  2133     
       
  2134     //Now let's set delivery report bits in MtmData
       
  2135     TMsvId link = 0;
       
  2136     if ( iMmsLog )
       
  2137         {
       
  2138         link = iMmsLog->GetLink();
       
  2139         }
       
  2140     if (link != 0)
       
  2141         {
       
  2142         error = iServerEntry->SetEntry(link);
       
  2143         if ( error == KErrNone )
       
  2144             {
       
  2145             entry = iServerEntry->Entry();
       
  2146             }
       
  2147         }
       
  2148 
       
  2149     // Even if the link exists, the original message may have disappeared already
       
  2150     // (if only 20 messages are saved in outbox, they may start disappearing quite fast)
       
  2151     if ( link != 0 && error == KErrNone && ( entry.iMtmData2 & KMmsDeliveryStatusMask ) !=
       
  2152         KMmsDeliveryStatusNotRequested )
       
  2153         {
       
  2154         TUint temp(0);
       
  2155         TUint total(0);
       
  2156         if (iDeliveryStatus) //Succesfully delivered
       
  2157             {
       
  2158             total = ( entry.iMtmData3 & KMmsSentItemTotalRecipientsMask ) >>
       
  2159                 KMmsSentItemTotalRecipientsShift;
       
  2160             
       
  2161             temp = ( entry.iMtmData3 & KMmsSentItemSuccessfullyDeliveredMask )
       
  2162                 >> KMmsSentItemSuccessfullyDeliveredShift;
       
  2163             temp++;
       
  2164             entry.iMtmData3 &= ~KMmsSentItemSuccessfullyDeliveredMask;
       
  2165             entry.iMtmData3 |= temp << KMmsSentItemSuccessfullyDeliveredShift;
       
  2166             
       
  2167             // must make sure that if even one send has been failed the delivery status
       
  2168             // is always failed
       
  2169             if ( temp == total  && ( entry.iMtmData2 & KMmsDeliveryStatusMask )
       
  2170                 != KMmsDeliveryStatysFailed )
       
  2171                 {
       
  2172                 entry.iMtmData2 &= ~KMmsDeliveryStatusMask;
       
  2173                 entry.iMtmData2 |= KMmsDeliveryStatysDelivered;
       
  2174                 }
       
  2175             else if (temp < total && ( entry.iMtmData2 & KMmsDeliveryStatusMask )
       
  2176                 != KMmsDeliveryStatysFailed  )
       
  2177                 {
       
  2178                 entry.iMtmData2 &= ~KMmsDeliveryStatusMask;
       
  2179                 entry.iMtmData2 |= KMmsDeliveryStatusPartial;
       
  2180                 }
       
  2181             else
       
  2182                 {
       
  2183                 // keep LINT happy
       
  2184                 }
       
  2185 
       
  2186             }
       
  2187         else 
       
  2188             {
       
  2189             temp = (entry.iMtmData3 & KMmsSentItemFailedDeliveryMask) >>
       
  2190                 KMmsSentItemFailedDeliveryShift;
       
  2191             temp++;
       
  2192             entry.iMtmData3 &= ~KMmsSentItemFailedDeliveryMask;
       
  2193             entry.iMtmData3 |= temp << KMmsSentItemFailedDeliveryShift;
       
  2194             entry.iMtmData2 &= ~KMmsDeliveryStatusMask;
       
  2195             entry.iMtmData2 |= KMmsDeliveryStatysFailed;
       
  2196                             
       
  2197             
       
  2198             }
       
  2199         // If we successfully accessed the entry, iServerEntry must still be pointing to the link.
       
  2200         iServerEntry->ChangeEntry(entry);    
       
  2201         }
       
  2202         
       
  2203     iError = KErrNone; // we don't care about the error.
       
  2204     // We should normally never be here, delivery reports come
       
  2205     // one at a time...
       
  2206     if ( iMsvSelection->Count() > 0 )
       
  2207         {
       
  2208         iScheduleSend->ReScheduleL( *iMsvSelection, aPackage );
       
  2209         }
       
  2210     }
       
  2211     
       
  2212 // ---------------------------------------------------------
       
  2213 // 
       
  2214 // ---------------------------------------------------------
       
  2215 //
       
  2216 void CMmsServerMtm::HandleFailedReadReports()
       
  2217     {
       
  2218     TInt error = KErrNone;
       
  2219     if ( iReadReport->Failed().Count() > 0 )
       
  2220         {
       
  2221         error = iServerEntry->SetEntry( iReadReport->Failed().At( 0 ) );
       
  2222         }
       
  2223     else
       
  2224         {
       
  2225         error = KErrNotFound;
       
  2226         }
       
  2227     if ( error == KErrNone )
       
  2228         {
       
  2229         error = iServerEntry->SetEntry( iServerEntry->Entry().Parent() );
       
  2230         }
       
  2231     if ( error == KErrNone )
       
  2232         {
       
  2233         TInt i;
       
  2234         for ( i = iReadReport->Failed().Count() - 1; i >= 0; i-- )
       
  2235             {
       
  2236             iServerEntry->DeleteEntry( iReadReport->Failed().At( i ) );
       
  2237             }
       
  2238         }
       
  2239     }
       
  2240    
       
  2241 // ---------------------------------------------------------
       
  2242 // 
       
  2243 // ---------------------------------------------------------
       
  2244 //
       
  2245 void CMmsServerMtm::MakeDatesIdenticalL(
       
  2246     CMsvEntrySelection& aSelection,
       
  2247     TTimeIntervalSeconds aInterval,
       
  2248     TBool aClearError /* = EFalse */ )
       
  2249     {
       
  2250 
       
  2251     TInt count = aSelection.Count();
       
  2252     TTime curTime;
       
  2253     curTime.UniversalTime();
       
  2254     if ( aInterval > TTimeIntervalSeconds( KMmsDelayInSeconds ) )
       
  2255         {
       
  2256         curTime += aInterval;
       
  2257         }
       
  2258     else
       
  2259         {
       
  2260         curTime += TTimeIntervalSeconds( KMmsDelayInSeconds );
       
  2261         }
       
  2262 
       
  2263     while ( count-- )
       
  2264         {
       
  2265         if ( iServerEntry->SetEntry( aSelection.At( count ) ) == KErrNone )
       
  2266             {
       
  2267             TMsvEntry entry = iServerEntry->Entry();
       
  2268             if ( entry.Id() != aSelection.At( count ) || entry.Id() == KMsvNullIndexEntryId )
       
  2269                 {
       
  2270                 // The entry is garbage
       
  2271                 aSelection.Delete( count, 1 );
       
  2272                 }
       
  2273             else
       
  2274                 {
       
  2275                 entry.iDate = curTime;
       
  2276                 if ( aClearError )
       
  2277                     {
       
  2278                     entry.iError = KErrNone;
       
  2279                     }
       
  2280                 iServerEntry->ChangeEntry( entry );
       
  2281                 }
       
  2282             }
       
  2283         }
       
  2284 
       
  2285     }
       
  2286 
       
  2287 // ---------------------------------------------------------
       
  2288 // CMmsServerMtm::DecodePushedMessageL()
       
  2289 // 
       
  2290 // ---------------------------------------------------------
       
  2291 //
       
  2292 void CMmsServerMtm::DecodePushedMessageL()
       
  2293     {
       
  2294 
       
  2295     // Decode the pushed content to see, if it was
       
  2296     // a notification or a delivery report
       
  2297 
       
  2298 #ifndef _NO_MMSS_LOGGING_
       
  2299     TMmsLogger::Log( _L("MmsServer decoding pushed message") );
       
  2300 #endif
       
  2301     iNotification = KMsvNullIndexEntryId;
       
  2302     iMmsHeaders->Reset();
       
  2303     // the possible error from this is not important as the settings are
       
  2304     // now stored in central repository
       
  2305     iServerEntry->SetEntry( iServiceEntryId );
       
  2306 
       
  2307     // We decode first, and create the entry afterwards.
       
  2308     if ( !iDecoder )
       
  2309         {
       
  2310         iDecoder = CMmsDecode::NewL( iFs );
       
  2311         }
       
  2312 
       
  2313     if ( !iEntryWrapper )
       
  2314         {
       
  2315         iEntryWrapper = CMmsServerEntry::NewL(
       
  2316             iFs,
       
  2317             *iServerEntry,
       
  2318             iServiceEntryId );
       
  2319         }
       
  2320 
       
  2321     TRAP ( iError, iDecoder->DecodeHeadersL( *iEntryWrapper, *iMmsHeaders, *iEncodeBuffer ) );
       
  2322 
       
  2323     // If we could not allocate memory to decode, we must try again later.
       
  2324     if ( iError == KErrNoMemory )
       
  2325         {
       
  2326         return;
       
  2327         }
       
  2328 
       
  2329     if ( iError == KErrCorrupt ||
       
  2330         iError == KErrTooBig )
       
  2331         {
       
  2332         // if the notification has illegal content,
       
  2333         // it is just discarded, we must not tell the
       
  2334         // mmswatcher to resend it.
       
  2335         iError = KErrNone;
       
  2336         return;
       
  2337         }
       
  2338     
       
  2339     // Even if we encounter an error when decoding, we must save
       
  2340     // the message for handling, because we must be able to send
       
  2341     // "unrecognized" status back, if we get an unknown PDU
       
  2342     // If we get a message with different major version number, it
       
  2343     // may be so incompatible that we get an error while decoding.
       
  2344 
       
  2345     // If we get a notification, we make some sanity checks so that 
       
  2346     // we can reject malicious notifications right away.
       
  2347 
       
  2348     // mark if this is a notification of a delivery report
       
  2349     // send requests or retrieve confirmations are not pushed
       
  2350     // They are equivalent to unrecognized type
       
  2351 
       
  2352     TUint32 messageType = 0;
       
  2353     switch ( iMmsHeaders->MessageType() )
       
  2354         {
       
  2355         case KMmsMessageTypeMNotificationInd:
       
  2356             messageType = KMmsMessageMNotificationInd;
       
  2357             break;
       
  2358         case KMmsMessageTypeDeliveryInd:
       
  2359             messageType = KMmsMessageDeliveryInd;
       
  2360             break;
       
  2361         case KMmsMessageTypeReadOrigInd:
       
  2362             messageType = KMmsMessageReadOrigInd;
       
  2363             break;
       
  2364         default:
       
  2365             // unrecognized type.
       
  2366             // We must send response to MMSC
       
  2367             // This includes types that should never be pushed to us.
       
  2368             messageType = KMmsMessageUnrecognized;
       
  2369             break;
       
  2370         }
       
  2371 
       
  2372     // If this is an extended notification, it may already contain the whole message
       
  2373     TBool completeMessage = ( iMmsHeaders->MessageComplete() == KMmsExtendedMessageComplete );
       
  2374 
       
  2375     TBool passedChecks = ETrue; // we are optimistic
       
  2376 
       
  2377     // If we have a notification, we must do a couple of special tricks.
       
  2378 
       
  2379     if ( messageType == KMmsMessageMNotificationInd )
       
  2380         {
       
  2381         // Some handling has been moved here from CMmsDecode,
       
  2382         // because it is better to have all notification logic in on place.
       
  2383 
       
  2384         // Expiry interval must be changed to absolute time,
       
  2385         // otherwise it makes no sense.
       
  2386         if ( iMmsHeaders->ExpiryDate() == 0 )
       
  2387             {
       
  2388             TTime time;
       
  2389             // handle expiry in universal time in case user changes location
       
  2390             time.UniversalTime();
       
  2391             time += TTimeIntervalSeconds( iMmsHeaders->ExpiryInterval() );
       
  2392             // we can't use "seconds from" as it only returns a
       
  2393             // 32 bit signed integer. If fails in 2038.
       
  2394             // "microseconds from" returns a 64 bit signed integer
       
  2395             // expiry date in iMmsHeaders in in seconds from 1.1.1970.
       
  2396             // interval must be changed back to seconds
       
  2397             // This way the result may still be a 64bit integer ->
       
  2398             // no overflow in 2038
       
  2399             iMmsHeaders->SetExpiryDate(
       
  2400                 ( time.MicroSecondsFrom( TTime( KMmsYear1970String ) ).Int64() ) / KMmsMillion );
       
  2401             }
       
  2402 
       
  2403         // Then we must check if the message type is acceptable.
       
  2404         // Rejection based on message type overrides the status
       
  2405         // set above. For example, if fetching is deferred, but
       
  2406         // we get an advertisement, and we don't accept advertisements
       
  2407         // we change the message status from deferred to rejected.
       
  2408         
       
  2409         switch ( iMmsHeaders->MessageClass() )
       
  2410             {
       
  2411             case EMmsClassPersonal:
       
  2412                 if ( iMmsSettings->AcceptPersonalMessages() == EFalse )
       
  2413                     {
       
  2414                     iMmsHeaders->SetStatus( KMmsMessageStatusRejected );
       
  2415                     }
       
  2416                 break;
       
  2417             case EMmsClassAdvertisement:
       
  2418                 if ( iMmsSettings->AcceptAdvertisementMessages() == EFalse ) 
       
  2419                     {
       
  2420                     iMmsHeaders->SetStatus( KMmsMessageStatusRejected );
       
  2421                     }
       
  2422                 break;
       
  2423             case EMmsClassInformational:
       
  2424                 if ( iMmsSettings->AcceptInformationalMessages() == EFalse )
       
  2425                     {
       
  2426                     iMmsHeaders->SetStatus( KMmsMessageStatusRejected );
       
  2427                     }
       
  2428                 break;
       
  2429             case EMmsClassAuto:
       
  2430                 // We accept automatic messages. The only automatic message we
       
  2431                 // know about is a text mode read report.
       
  2432                 // As we now handle read reports, we must accept automatic messages
       
  2433                 // in case some server has converted a read report into a text message
       
  2434                 // (possible if the server does not recognize the phone and know its
       
  2435                 // capabilities).
       
  2436                 break;
       
  2437             default:
       
  2438                 // if we cannot determine the message type,
       
  2439                 // we reject it.
       
  2440                 // Message class header is mandatory in notification
       
  2441                 //iMmsHeaders->SetStatus( KMmsMessageStatusRejected );
       
  2442                 break;
       
  2443             }
       
  2444         // check if we accept anonymous messages
       
  2445         if ( iMmsSettings->AcceptAnonymousMessages() == EFalse &&
       
  2446             iMmsHeaders->Sender().Length() == 0 )
       
  2447             {
       
  2448 #ifndef _NO_MMSS_LOGGING_
       
  2449             TMmsLogger::Log( _L("- Anonymous message rejected") );
       
  2450 #endif
       
  2451             iMmsHeaders->SetStatus( KMmsMessageStatusRejected );
       
  2452             }
       
  2453             
       
  2454         // If the encapsulation version is 1.3, the notification may already
       
  2455         // contain the application id header.
       
  2456         // If the application has not been registered, we reject the message
       
  2457         // (at least until more complex support for the applicatiom message
       
  2458         // handling has been implemented)
       
  2459         if ( iMmsHeaders->ApplicId().Length() > 0 )
       
  2460             {
       
  2461             if ( !CMmsBaseOperation::RegisteredL( iMmsHeaders->ApplicId() ) )
       
  2462                 {
       
  2463                 iMmsHeaders->SetStatus( KMmsMessageStatusRejected );
       
  2464                 }
       
  2465             }
       
  2466 
       
  2467         // if the extended notification contains the whole message
       
  2468         // we must mark it as "retrieved"
       
  2469         // If there is an extended message addressed to an application,
       
  2470         // it is something that cannot be reasonably handled.
       
  2471         // I hope that is an illegal case anyway.
       
  2472 
       
  2473         if ( completeMessage )
       
  2474             {
       
  2475             iMmsHeaders->SetStatus( 0 ); // not applicable
       
  2476             }
       
  2477 
       
  2478         // legality checks:
       
  2479         // TID is mandatory
       
  2480         if ( iMmsHeaders->Tid().Length() == 0 )
       
  2481             {
       
  2482             passedChecks = EFalse;
       
  2483 #ifndef _NO_MMSS_LOGGING_
       
  2484             TMmsLogger::Log( _L("- invalid TID: length = %d"), iMmsHeaders->Tid().Length() );
       
  2485 #endif
       
  2486             }
       
  2487         // message class is mandatory
       
  2488         if ( iMmsHeaders->MessageClass() == 0 )
       
  2489             {
       
  2490             passedChecks = EFalse;
       
  2491 #ifndef _NO_MMSS_LOGGING_
       
  2492             TMmsLogger::Log( _L("- message class not defined") );
       
  2493 #endif
       
  2494             }
       
  2495 
       
  2496         // Messages with zero length must be accepted if message size may be
       
  2497         // just the size of payload and subject (both may have zero length)
       
  2498         // If headers are not included in calculation, zero length is acceptable here.
       
  2499 
       
  2500         // expiry is mandatory - but it cannot be 0 because we just set it.
       
  2501         // If expiry is not given, the notification expires NOW
       
  2502         
       
  2503         // content location is mandatory
       
  2504         if ( iMmsHeaders->ContentLocation().Length() == 0 )
       
  2505             {
       
  2506             passedChecks = EFalse;
       
  2507 #ifndef _NO_MMSS_LOGGING_
       
  2508             TMmsLogger::Log( _L("- no content location") );
       
  2509 #endif
       
  2510             }
       
  2511         }
       
  2512 
       
  2513     // if we have notification that does not fill our
       
  2514     // criteria, we just throw it away. The purpose of this
       
  2515     // is to discard possible malignant notifications that
       
  2516     // would cause us to contact some unknown server and
       
  2517     // do strange damage - or at least cause unncessary
       
  2518     // network traffic.
       
  2519 
       
  2520     // If the message is complete, we keep it anyway
       
  2521 
       
  2522     if ( passedChecks == EFalse && !completeMessage )
       
  2523         {
       
  2524         iError = KErrNone;
       
  2525         return;
       
  2526         }
       
  2527 
       
  2528     TMsvEntry tEntry;
       
  2529     tEntry.iType = KUidMsvMessageEntry;
       
  2530     // This may be different for notifications in manual modes
       
  2531     // This is ok, as all notifications are stored first to the internal MMS folder
       
  2532     tEntry.iMtm = KUidMsgTypeMultimedia;
       
  2533 
       
  2534     // use the iRelatedId to bypass queue.
       
  2535     tEntry.iServiceId = KMsvLocalServiceIndexEntryId;
       
  2536     tEntry.iRelatedId = iServiceEntryId;
       
  2537     tEntry.SetUnread( ETrue );
       
  2538     tEntry.SetNew( ETrue );
       
  2539     tEntry.SetVisible( EFalse );
       
  2540     tEntry.SetComplete( EFalse );
       
  2541     tEntry.SetInPreparation( ETrue );
       
  2542     tEntry.SetReadOnly( EFalse );
       
  2543     tEntry.iSize = iMmsHeaders->Size();
       
  2544     
       
  2545     //
       
  2546     // Setting StoredInMMBox flag correctly
       
  2547     //
       
  2548     HandleMMBoxFlagL( tEntry );
       
  2549 
       
  2550     // Notifications are always originally children of MMS Folder
       
  2551     // We have decoded our headers already.
       
  2552     // We know if this is a notification or a delivery report,
       
  2553     // and we can decide what to do.
       
  2554 
       
  2555     TMsvId parent = KMsvNullIndexEntryId;
       
  2556     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  2557     TMsvId mmsFolder = FindMMSFolderL();
       
  2558     if ( mmsFolder == KMsvNullIndexEntryId )
       
  2559         {
       
  2560         // If the id for our notification folder is 0, we are really in a mess
       
  2561         // and cannot continue
       
  2562         iError = KErrNotFound;
       
  2563         return;
       
  2564         }
       
  2565     parent = mmsFolder;
       
  2566 
       
  2567     if ( messageType != KMmsMessageDeliveryInd &&
       
  2568          messageType != KMmsMessageReadOrigInd &&
       
  2569          messageType != KMmsMessageReadRecInd ) 
       
  2570         { 
       
  2571         // Check duplicates from parent folder, from Inbox and from mmbox folder 
       
  2572         // no mater which receiving mode is on.
       
  2573         TMsvId mmboxFolder = iMmsSettings->MMBoxFolder();
       
  2574         if ( PruneDuplicateNotificationsL( parent, *iMmsHeaders ) ||
       
  2575             PruneDuplicateNotificationsL( KMsvGlobalInBoxIndexEntryIdValue, *iMmsHeaders ) ||
       
  2576             PruneDuplicateNotificationsL( mmboxFolder, *iMmsHeaders ))
       
  2577             {
       
  2578 #ifndef _NO_MMSS_LOGGING_
       
  2579             TMmsLogger::Log( _L("- duplicate - not stored") );
       
  2580 #endif
       
  2581             iError = KErrNone;
       
  2582             return;
       
  2583             }
       
  2584         }
       
  2585 
       
  2586     // If this is an extended notification that contains the whole message
       
  2587     // the entry goes to inbox as a message, not a notification.
       
  2588     // The fetching must not be scheduled in this case as we already have the
       
  2589     // message.
       
  2590     // However, if we are in home network, we must send acknowledge back to MMSC
       
  2591     // Besides storing the notification as message entry, we must create another
       
  2592     // entry to serve as base for sending the acknowledgement. Therefore we have
       
  2593     // marked our status as "KMmsMessageStatusRetrieved"
       
  2594 
       
  2595     // this is the size of the attachment if we have an extended notification
       
  2596     TInt attaSize = 0;
       
  2597 
       
  2598     if ( completeMessage )
       
  2599         {
       
  2600         parent = KMsvGlobalInBoxIndexEntryIdValue;
       
  2601         tEntry.iMtm = KUidMsgTypeMultimedia;
       
  2602         // indicate complete message
       
  2603         iMmsHeaders->SetMessageType( KMmsMessageTypeMRetrieveConf );
       
  2604         }
       
  2605 
       
  2606     // If we can't access the parent where the notification is to be stored,
       
  2607     // we can do nothing
       
  2608     iError = iServerEntry->SetEntry( parent );
       
  2609     if ( iError != KErrNone )
       
  2610         {
       
  2611         return; // cannot continue
       
  2612         }
       
  2613 
       
  2614     // Query about disk space. KMmsIndexEntryExtra is extra for TMsvEntry
       
  2615     // Make one query, we assume no one takes away the disk space this fast.
       
  2616     if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL(
       
  2617         &iFs, iMmsHeaders->Size() + KMmsIndexEntryExtra + iMmsHeaders->Size(), iMessageDrive ) )
       
  2618         {
       
  2619         // we use standard error code here
       
  2620         iError = KErrDiskFull;
       
  2621         return; // cannot continue
       
  2622         }
       
  2623 
       
  2624     iError = iServerEntry->CreateEntry( tEntry );
       
  2625 
       
  2626     if ( iError == KErrNone )
       
  2627         {
       
  2628         iError = iServerEntry->SetEntry( tEntry.Id() );
       
  2629         iNotification = tEntry.Id();
       
  2630         }
       
  2631 
       
  2632     CMsvStore* store = NULL;
       
  2633     HBufC* buffer = NULL; // we need this to generate a description for the entry
       
  2634     TBool attachmentAdded = EFalse; // to track if the extended notification text has been added to the message store or not.   
       
  2635 
       
  2636     if ( iError == KErrNone )
       
  2637         {
       
  2638         // if this is a whole message, create an attachment from the text
       
  2639         if ( completeMessage && iNotification != KMsvNullIndexEntryId )
       
  2640             {
       
  2641             tEntry = iServerEntry->Entry(); // save the settings we have so far
       
  2642             if ( iMmsHeaders->Subject().Length() > 0 )
       
  2643                 {
       
  2644                 tEntry.iDescription.Set( iMmsHeaders->Subject() );
       
  2645                 }
       
  2646             else
       
  2647                 {
       
  2648                 // Save text as description if we have no subject
       
  2649                 TPtrC temp = iMmsHeaders->ExtendedNotification().Left( KMmsMaxDescription );
       
  2650                 buffer = HBufC::NewL( temp.Length() );
       
  2651                 // no need to put buffer onto cleanup stack - we don't leave before we are done
       
  2652                 buffer->Des().Copy( temp );
       
  2653                 TPtr pDescription = buffer->Des();
       
  2654                 TMmsGenUtils::ReplaceCRLFAndTrim( pDescription );
       
  2655                 tEntry.iDescription.Set( pDescription );
       
  2656                 }
       
  2657             iServerEntry->ChangeEntry( tEntry );
       
  2658             // If we have not allocated the buffer, it is NULL, and it is safe to delete.
       
  2659             delete buffer;
       
  2660             buffer = NULL;
       
  2661 
       
  2662             if ( iMmsHeaders->ExtendedNotification().Length() > 0 )
       
  2663                 {
       
  2664                 TMsvAttachmentId attachmentId = 0;
       
  2665                 CMsvMimeHeaders* mimeHeaders = CMsvMimeHeaders::NewL();
       
  2666                 CleanupStack::PushL( mimeHeaders );
       
  2667                 TPtrC8 temp;
       
  2668                 temp.Set( KMmsTextPlain );
       
  2669                 mimeHeaders->SetContentTypeL( temp.Left( temp.Find( KMmsSlash8 ) ) );
       
  2670                 mimeHeaders->SetContentSubTypeL( temp.Mid( temp.Find( KMmsSlash8 ) + 1 ) );
       
  2671                 mimeHeaders->SetMimeCharset( KMmsUtf8 ); // text saved as utf-8
       
  2672                 _LIT( KRelated, "att1.txt");
       
  2673                 mimeHeaders->SetSuggestedFilenameL( KRelated );
       
  2674                 // attaData must point to the text
       
  2675                 // buffer long enough for conversion
       
  2676                 const TInt KMmsConversionMultiplier = 5;
       
  2677                 HBufC8* dataContent = HBufC8::NewL(
       
  2678                     iMmsHeaders->ExtendedNotification().Length() * KMmsConversionMultiplier );
       
  2679                 CleanupStack::PushL( dataContent );
       
  2680                 TPtr8 attaData = dataContent->Des();
       
  2681                 CnvUtfConverter::ConvertFromUnicodeToUtf8(
       
  2682                     attaData, iMmsHeaders->ExtendedNotification() );
       
  2683                 // set parent
       
  2684                 iError = iEntryWrapper->SetCurrentEntry( iNotification );
       
  2685                 
       
  2686                 if ( iError == KErrNone )
       
  2687                     {
       
  2688                     store = iEntryWrapper->EditStoreL();
       
  2689                     CleanupStack::PushL( store );
       
  2690                     TInt32 drmFlags = 0; //ignored
       
  2691                     iError = iEntryWrapper->CreateFileAttachmentL(
       
  2692                         *store,
       
  2693                         KRelated,
       
  2694                         attaData,
       
  2695                         *mimeHeaders,
       
  2696                         attachmentId,
       
  2697                         attaSize,
       
  2698                         drmFlags);
       
  2699 			        //If attachment is added to Message store successfully then attachmentAdded is set
       
  2700 			        if ( iError == KErrNone )
       
  2701 			            {
       
  2702                         attachmentAdded = ETrue;
       
  2703 			            }    
       
  2704                     store->CommitL();
       
  2705                     CleanupStack::PopAndDestroy( store );
       
  2706                     store = NULL;
       
  2707                     }
       
  2708                 iMmsHeaders->SetExtendedNotificationL( TPtrC() );
       
  2709                 
       
  2710                 CleanupStack::PopAndDestroy( dataContent );
       
  2711                 CleanupStack::PopAndDestroy( mimeHeaders );
       
  2712                 }
       
  2713             }
       
  2714         if ( iServerEntry->SetEntry( iNotification ) == KErrNone &&
       
  2715             iNotification != KMsvNullIndexEntryId )
       
  2716             {
       
  2717             store = iServerEntry->EditStoreL();
       
  2718             CleanupStack::PushL(store);
       
  2719             iMmsHeaders->StoreL(*store);
       
  2720             store->CommitL();
       
  2721             CleanupStack::PopAndDestroy( store );
       
  2722             store = NULL;
       
  2723             }
       
  2724         }
       
  2725 
       
  2726 
       
  2727     if ( ( iError == KErrNone || iMmsHeaders->MessageType() != 0 )
       
  2728         && iNotification != KMsvNullIndexEntryId )
       
  2729         {
       
  2730         iError = iServerEntry->SetEntry( iNotification );
       
  2731         if ( iError != KErrNone )
       
  2732             {
       
  2733             // If we have an error here, there is something
       
  2734             // seriously wrong with the system
       
  2735             if ( iServerEntry->SetEntry( parent ) == KErrNone )
       
  2736                 {
       
  2737                 iServerEntry->DeleteEntry( iNotification );
       
  2738                 }
       
  2739             iNotification = KMsvNullIndexEntryId;
       
  2740             iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  2741             return; // cannot continue
       
  2742             }
       
  2743         }
       
  2744     else
       
  2745         {
       
  2746         if ( iServerEntry->SetEntry( parent ) == KErrNone &&
       
  2747             iNotification != KMsvNullIndexEntryId )
       
  2748             {
       
  2749             // We managed to create an entry, but not to decode
       
  2750             // the buffer contents into the entry
       
  2751             iServerEntry->DeleteEntry( iNotification );
       
  2752             }
       
  2753         iNotification = KMsvNullIndexEntryId;
       
  2754         iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  2755         return;
       
  2756         }
       
  2757 
       
  2758     // finish the details, and the notification entry is ready to be used
       
  2759     tEntry = iServerEntry->Entry();
       
  2760     
       
  2761     if ( messageType == KMmsMessageMNotificationInd )
       
  2762         {
       
  2763         // If the sender is a phone number, add alias.
       
  2764         // We don't add alias for email addresses here, as the contact
       
  2765         // database search for email addresses is very slow
       
  2766         // if there are lots of contacts.
       
  2767         buffer = HBufC::NewL( KMmsMaxDescription );
       
  2768         CleanupStack::PushL( buffer );
       
  2769         
       
  2770         TPtr pBuffer = buffer->Des();
       
  2771 
       
  2772         if ( TMmsGenUtils::GenerateDetails( iMmsHeaders->Sender(),
       
  2773             pBuffer, KMmsMaxDescription, iFs ) == KErrNone )
       
  2774             {
       
  2775             tEntry.iDetails.Set( pBuffer );
       
  2776             }
       
  2777         else
       
  2778             {
       
  2779             // We come here only if there was an fatal error in GenerateDetails.
       
  2780             // Even if we don't find the alias, we have something in the string
       
  2781             tEntry.iDetails.Set( iMmsHeaders->Sender() );
       
  2782             }
       
  2783 
       
  2784         // set subject if available
       
  2785         if ( iMmsHeaders->Subject().Length() > 0 )
       
  2786             {
       
  2787             tEntry.iDescription.Set( iMmsHeaders->Subject() );
       
  2788             }
       
  2789         CleanupStack::Pop( buffer );
       
  2790 
       
  2791         }
       
  2792     else if ( messageType == KMmsMessageDeliveryInd &&
       
  2793         iMmsHeaders->ToRecipients().MdcaCount() > 0 )
       
  2794         {
       
  2795         tEntry.iDetails.Set( iMmsHeaders->ToRecipients().MdcaPoint( 0 ) );
       
  2796         }
       
  2797     else
       
  2798         {
       
  2799         // keep LINT happy
       
  2800         }
       
  2801 
       
  2802     tEntry.iMtmData1 &= ~KMmsMessageTypeMask;
       
  2803     tEntry.iMtmData1 |= messageType;
       
  2804     if ( iMmsHeaders->MessageClass() == EMmsClassAdvertisement )
       
  2805         {
       
  2806         tEntry.iMtmData1 |= KMmsMessageAdvertisement;
       
  2807         }
       
  2808     else if ( iMmsHeaders->MessageClass() == EMmsClassInformational )
       
  2809         {
       
  2810         tEntry.iMtmData1 |= KMmsMessageInformational;
       
  2811         }
       
  2812     else
       
  2813         {
       
  2814         // keep LINT happy
       
  2815         }
       
  2816         
       
  2817     switch ( iMmsHeaders->MessagePriority() )
       
  2818         {
       
  2819         case KMmsPriorityNormal:
       
  2820             tEntry.SetPriority( EMsvMediumPriority );
       
  2821             break;
       
  2822         case KMmsPriorityLow:
       
  2823             tEntry.SetPriority( EMsvLowPriority );
       
  2824             break;
       
  2825         case KMmsPriorityHigh:
       
  2826             tEntry.SetPriority( EMsvHighPriority );
       
  2827             break;
       
  2828         default:            
       
  2829             // if not defined default is normal
       
  2830             tEntry.SetPriority( EMsvMediumPriority );
       
  2831             break;
       
  2832         }
       
  2833         
       
  2834     tEntry.SetVisible( ETrue );
       
  2835     tEntry.SetComplete( ETrue );
       
  2836     tEntry.SetInPreparation( EFalse );
       
  2837     tEntry.SetReadOnly( EFalse );
       
  2838     tEntry.iDate.UniversalTime(); // This is arrival time
       
  2839     tEntry.iSize = iMmsHeaders->Size() + attaSize; // add attachment data + mime headers
       
  2840 
       
  2841     // Set values to correspond to a new message if this was an extended notification
       
  2842     // containing full text.
       
  2843 
       
  2844     if ( completeMessage )
       
  2845         {
       
  2846         tEntry.iMtmData1 &= ~KMmsMessageTypeMask;
       
  2847         // We override message type.
       
  2848         tEntry.iMtmData1 |= KMmsMessageMRetrieveConf | KMmsMessageMobileTerminated;
       
  2849         tEntry.SetReadOnly( ETrue );
       
  2850         tEntry.SetSendingState( KMsvSendStateSent );
       
  2851         tEntry.iServiceId = iServiceEntryId;
       
  2852         if ( attachmentAdded )
       
  2853             {
       
  2854         	tEntry.SetAttachment(ETrue);
       
  2855             }
       
  2856         }
       
  2857 
       
  2858     // we mark delivery reports as already sent so that
       
  2859     // we get rid of them at next garbage collecion, if the phone
       
  2860     // boots or crashes before they are handled.
       
  2861     // Delivery reports are lost if phone crashes.
       
  2862     if ( messageType == KMmsMessageDeliveryInd ||
       
  2863          messageType == KMmsMessageReadOrigInd )
       
  2864         {
       
  2865         tEntry.SetSendingState( KMsvSendStateSent );
       
  2866         }
       
  2867 
       
  2868     iServerEntry->ChangeEntry( tEntry ); // ignore any error
       
  2869     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  2870 
       
  2871     delete buffer;
       
  2872     buffer = NULL;
       
  2873 
       
  2874     // If the message was complete, we have put our notification to inbox, and it is ready to be used.
       
  2875     // However, we still need an entry for sending back an acknowledgement to the server.
       
  2876     // We must create a new new notification entry for that purpose.
       
  2877 
       
  2878     if ( completeMessage )
       
  2879         {
       
  2880         // don't schedule the entry that went into inbox
       
  2881         iNotification = KMsvNullIndexEntryId;
       
  2882         TInt error = KErrNone;
       
  2883         tEntry.iType = KUidMsvMessageEntry; // This will never go to inbox
       
  2884         tEntry.iMtm = KUidMsgTypeMultimedia;
       
  2885         tEntry.iServiceId = iServiceEntryId;
       
  2886         tEntry.iRelatedId = iServiceEntryId;
       
  2887         tEntry.SetUnread( ETrue );
       
  2888         tEntry.SetNew( ETrue );
       
  2889         tEntry.SetVisible( EFalse );
       
  2890         tEntry.SetComplete( EFalse );
       
  2891         tEntry.SetInPreparation( ETrue );
       
  2892         tEntry.SetReadOnly( EFalse );
       
  2893         tEntry.iSize = iMmsHeaders->Size();
       
  2894         tEntry.SetSendingState( KMsvSendStateUnknown );
       
  2895         tEntry.iDescription.Set( iMmsHeaders->Subject() );
       
  2896         tEntry.iMtmData1 &= ~KMmsMessageTypeMask;
       
  2897         tEntry.iMtmData1 |= KMmsMessageMNotificationInd;
       
  2898         // even if sending ack fails, this must not be moved to inbox
       
  2899         // because the corresponding message already is there.
       
  2900         tEntry.iMtmData2 |= KMmsDoNotMoveToInbox; 
       
  2901         parent = mmsFolder;
       
  2902         error = iServerEntry->SetEntry( parent );
       
  2903         if ( error == KErrNone )
       
  2904             {
       
  2905             error = iServerEntry->CreateEntry( tEntry );
       
  2906             }
       
  2907         if ( error == KErrNone )
       
  2908             {
       
  2909             iError = iServerEntry->SetEntry( tEntry.Id() );
       
  2910             if ( iError == KErrNone )
       
  2911                 {
       
  2912                 // Now we have a new entry that will be scheduled for sending the acknowledgement
       
  2913                 iNotification = tEntry.Id();
       
  2914                 iMmsHeaders->SetStatus( KMmsMessageStatusRetrieved );
       
  2915                 iMmsHeaders->SetMessageType( KMmsMessageTypeMNotificationInd );
       
  2916                 store = iServerEntry->EditStoreL();
       
  2917                 CleanupStack::PushL( store );
       
  2918                 iMmsHeaders->StoreL( *store );
       
  2919                 store->CommitL();
       
  2920                 CleanupStack::PopAndDestroy( store );
       
  2921                 store = NULL;
       
  2922                 tEntry.SetVisible( ETrue );
       
  2923                 tEntry.SetComplete( ETrue );
       
  2924                 tEntry.SetInPreparation( EFalse );
       
  2925                 iServerEntry->ChangeEntry( tEntry ); // ignore any error
       
  2926                 }
       
  2927             }
       
  2928         }
       
  2929 
       
  2930 #ifndef _NO_MMSS_LOGGING_
       
  2931     // log a little bit of something
       
  2932     if ( messageType == KMmsMessageDeliveryInd )
       
  2933         {
       
  2934         TMmsLogger::Log( _L("- delivery report received") );
       
  2935         }
       
  2936     else if ( messageType == KMmsMessageMNotificationInd )
       
  2937         {
       
  2938         TMmsLogger::Log( _L("- notification received") );
       
  2939         }
       
  2940     else
       
  2941         {
       
  2942         TMmsLogger::Log( _L("- pushed message of type %d received"), messageType );
       
  2943         }
       
  2944 #endif
       
  2945 
       
  2946     }
       
  2947 
       
  2948 // ---------------------------------------------------------
       
  2949 // CMmsServerMtm::HandleNotificationL()
       
  2950 // 
       
  2951 // ---------------------------------------------------------
       
  2952 //
       
  2953 void CMmsServerMtm::HandleNotificationL()
       
  2954     {
       
  2955 #ifndef _NO_MMSS_LOGGING_
       
  2956     TMmsLogger::Log( _L("MmsServer HandleNotification, %d items"), iMsvSelection->Count() );
       
  2957 #endif
       
  2958     if ( iMsvSelection->Count() < 1 )
       
  2959         {
       
  2960         // nothing to do, give up
       
  2961         *iRequestStatus = KRequestPending;
       
  2962         User::RequestComplete( iRequestStatus, iError );
       
  2963         return;
       
  2964         }
       
  2965 
       
  2966     // If both receiving modes in home and foreign network are "reject".
       
  2967     // The notification is deleted.
       
  2968     if( iMmsSettings->ReceivingModeHome() == EMmsReceivingReject &&
       
  2969         iMmsSettings->ReceivingModeForeign() == EMmsReceivingReject )
       
  2970         {
       
  2971         // we play possum and delete the notification without
       
  2972         // sending any response to MMSC.
       
  2973 #ifndef _NO_MMSS_LOGGING_
       
  2974         TMmsLogger::Log( _L("- playing possum, deleting notifications") );
       
  2975 #endif
       
  2976         TInt count = iMsvSelection->Count();
       
  2977         TMsvEntry entry;
       
  2978         TMsvId parent = KMsvNullIndexEntryId;
       
  2979         if ( iServerEntry->SetEntry( iMsvSelection->At( count - 1 ) ) == KErrNone ) 
       
  2980             {
       
  2981             entry = iServerEntry->Entry();
       
  2982             parent = entry.Parent();
       
  2983             }
       
  2984         while ( count-- && parent != KMsvNullIndexEntryId )
       
  2985             {
       
  2986             if ( iServerEntry->SetEntry( iMsvSelection->At( count ) ) == KErrNone )
       
  2987                 {
       
  2988                 entry = iServerEntry->Entry();
       
  2989                 parent = entry.Parent();
       
  2990                 }
       
  2991             
       
  2992             if ( iServerEntry->SetEntry( parent ) == KErrNone )
       
  2993                 {
       
  2994                 iServerEntry->DeleteEntry( iMsvSelection->At( count ) );
       
  2995                 }
       
  2996             }
       
  2997         *iRequestStatus = KRequestPending;
       
  2998         User::RequestComplete( iRequestStatus, iError );
       
  2999         return;
       
  3000         }
       
  3001         
       
  3002     // When the notificatio arrived, it was checked, and if it was
       
  3003     // a duplicate of an earlier one, it was not saved on disk.
       
  3004 
       
  3005     iCommand = EMmsReceive;
       
  3006            
       
  3007     // ScheduleL completes our caller
       
  3008     // we want to get back to out RunL to check the error
       
  3009     // Query about disk space.
       
  3010     // Subroutine knows how much must be checked for task scheduler
       
  3011     TInt error = KErrNone;
       
  3012     if ( DiskSpaceBelowCriticalForSchedulingL( &iFs, 0, iMessageDrive ) )
       
  3013         {
       
  3014 		// we use standard error code here
       
  3015 		#ifndef _NO_MMSS_LOGGING_
       
  3016 		TMmsLogger::Log( _L("HandleNotificationL.. Disk Full") );
       
  3017 		#endif
       
  3018 		error = KErrDiskFull;
       
  3019 		TInt count = iMsvSelection->Count();
       
  3020 		TMsvEntry entry;
       
  3021 		if ( iServerEntry->SetEntry( iMsvSelection->At( count - 1 ) ) == KErrNone ) 
       
  3022 		    {
       
  3023 			entry = iServerEntry->Entry();
       
  3024 			entry.iError = error;
       
  3025 			iServerEntry->ChangeEntry( entry );
       
  3026 			#ifndef _NO_MMSS_LOGGING_
       
  3027 			TMmsLogger::Log( _L("HandleNotificationL.. Setting ierror to Entry") );
       
  3028 			#endif
       
  3029 		    }
       
  3030         
       
  3031         }
       
  3032     else
       
  3033         {
       
  3034         // We must set the caller's status to KRequest Pending because
       
  3035         // CScheduleBaseServerMtm::ScheduleL does not do it.
       
  3036         *iRequestStatus = KRequestPending;
       
  3037         TRAP( error, ScheduleL( *iMsvSelection, EFalse, KNullDesC8, *iRequestStatus ) );
       
  3038         // ScheduleL would complete our caller, but if it leaves,
       
  3039         // we must complete. We don't want to leave...
       
  3040         }
       
  3041     if ( error != KErrNone )
       
  3042         {
       
  3043 #ifndef _NO_MMSS_LOGGING_
       
  3044         TMmsLogger::Log( _L("MmsServer HandleNotification status %d"), error );
       
  3045 #endif
       
  3046         *iRequestStatus = KRequestPending;
       
  3047         User::RequestComplete( iRequestStatus, error );
       
  3048         }
       
  3049 
       
  3050     }
       
  3051 
       
  3052 // ---------------------------------------------------------
       
  3053 // CMmsServerMtm::HandleDeliveryReportL()
       
  3054 // 
       
  3055 // ---------------------------------------------------------
       
  3056 //
       
  3057 void CMmsServerMtm::HandleDeliveryReportL()
       
  3058     {
       
  3059 
       
  3060     if ( iMsvSelection->Count() < 1 )
       
  3061         {
       
  3062         // nothing to do, give up
       
  3063         *iRequestStatus = KRequestPending;
       
  3064         User::RequestComplete( iRequestStatus, iError );
       
  3065         return;
       
  3066         }
       
  3067     
       
  3068     iCommand = EMmsLogDeliveryReport;
       
  3069            
       
  3070     // Query about disk space.
       
  3071     // Subroutine knows how much must be checked for task scheduler
       
  3072     TInt error = KErrNone;
       
  3073     if ( DiskSpaceBelowCriticalForSchedulingL( &iFs, 0, iMessageDrive ) )
       
  3074         {
       
  3075         // we use standard error code here
       
  3076         error = KErrDiskFull;
       
  3077         }
       
  3078     else
       
  3079         {
       
  3080         // ScheduleL completes our caller
       
  3081         // We must set the caller's status to KRequest Pending because
       
  3082         // CScheduleBaseServerMtm::ScheduleL does not do it.
       
  3083         *iRequestStatus = KRequestPending;
       
  3084         TRAP( error, ScheduleL( *iMsvSelection, EFalse, KNullDesC8, *iRequestStatus ) );
       
  3085         // ScheduleL would complete our caller, but if it leaves,
       
  3086         // we must complete. We don't want to leave...
       
  3087         }
       
  3088     if ( error != KErrNone )
       
  3089         {
       
  3090 #ifndef _NO_MMSS_LOGGING_
       
  3091         TMmsLogger::Log( _L("MmsServer HandleDeliveryReport status %d"), error );
       
  3092 #endif
       
  3093         *iRequestStatus = KRequestPending;
       
  3094         User::RequestComplete( iRequestStatus, error );
       
  3095         }
       
  3096     }
       
  3097 
       
  3098 
       
  3099 // ---------------------------------------------------------
       
  3100 // CMmsServerMtm::LogDeliveryReportL()
       
  3101 // 
       
  3102 // ---------------------------------------------------------
       
  3103 //
       
  3104 void CMmsServerMtm::LogDeliveryReportL()
       
  3105     {
       
  3106 
       
  3107 #ifndef _NO_MMSS_LOGGING_
       
  3108     TMmsLogger::Log( _L("MmsServer Logging delivery report") );
       
  3109 #endif
       
  3110     // this subroutine does not do critical disk space level check
       
  3111     // normally we just update an existing entry changing only status
       
  3112     // which does not change disk space usage.
       
  3113     // Only if our previous entry has been deleted, we add something.
       
  3114     // We don't check that. The amount of disk space needed should
       
  3115     // be less than 100 bytes anyway. Large messages are more critical
       
  3116     // than small log entries.
       
  3117 
       
  3118     if ( iMsvSelection->Count() < 1 )
       
  3119         {
       
  3120         // nothing to do, give up
       
  3121         // we complete our caller
       
  3122         *iRequestStatus = KRequestPending;
       
  3123         User::RequestComplete( iRequestStatus, iError );
       
  3124         return;
       
  3125         }
       
  3126     
       
  3127     iCommand = EMmsLogDeliveryReport;
       
  3128     TRequestStatus* status = &iStatus;
       
  3129     TBool readReport = EFalse; // first guess - delivery report
       
  3130 
       
  3131     iError = iServerEntry->SetEntry( iMsvSelection->At( 0 ) );
       
  3132     if ( iError == KErrNotFound )
       
  3133         {
       
  3134         // The entry we are supposed to handle has disappeared.
       
  3135         // We complete the active object.
       
  3136         // RunL will call UpdateEntriesL, and that function
       
  3137         // will delete the entry from the list, and try the next
       
  3138         // one, if it exists.
       
  3139         // We must set the error to "none" to delete the entry
       
  3140         // instead of retrying.
       
  3141         iError = KErrNone;
       
  3142         // get back to our own RunL, it will complete caller
       
  3143         *iRequestStatus = KRequestPending;
       
  3144         iStatus = KRequestPending;
       
  3145         SetActive();
       
  3146         User::RequestComplete( status, iError );
       
  3147         return;
       
  3148         }
       
  3149 
       
  3150     TMsvEntry entry;
       
  3151     if ( iError == KErrNone )
       
  3152         {
       
  3153         entry = iServerEntry->Entry();
       
  3154         }
       
  3155     else
       
  3156         {
       
  3157         // cannot access entry.
       
  3158 #ifndef _NO_MMSS_LOGGING_
       
  3159         TMmsLogger::Log( _L("MmsServer could not access delivery report") );
       
  3160 #endif
       
  3161         // Retry later.
       
  3162         // now our error is not KErrNone, so we will reschedule
       
  3163         // in UpdateEntriesL
       
  3164         *iRequestStatus = KRequestPending;
       
  3165         iStatus = KRequestPending;
       
  3166         SetActive();
       
  3167         User::RequestComplete( status, iError );
       
  3168         }
       
  3169         
       
  3170     if ( ( entry.iMtmData1 & KMmsMessageTypeMask ) == KMmsMessageReadOrigInd )
       
  3171         {
       
  3172         // The remote party is in "From" field because that's the recipient
       
  3173         // that is sending the read report
       
  3174         readReport = ETrue;
       
  3175         }
       
  3176     else if ( ( entry.iMtmData1 & KMmsMessageTypeMask ) != KMmsMessageDeliveryInd )
       
  3177         {
       
  3178         iError = KErrNone;
       
  3179         // get back to our own RunL
       
  3180         *iRequestStatus = KRequestPending;
       
  3181         iStatus = KRequestPending;
       
  3182         SetActive();
       
  3183         User::RequestComplete( status, iError );
       
  3184         return;
       
  3185         }
       
  3186     
       
  3187     if ( !iMmsLog )
       
  3188         {
       
  3189         iLogClient = CLogClient::NewL( iFs );
       
  3190         iLogViewEvent = CLogViewEvent::NewL( *iLogClient );
       
  3191         iMmsLog = CMmsLog::NewL( *iLogClient, *iLogViewEvent, iFs );
       
  3192         }
       
  3193 
       
  3194     if ( !iLogEvent )
       
  3195         {
       
  3196         iLogEvent = CLogEvent::NewL();
       
  3197         }
       
  3198 
       
  3199     if ( !iRemoteParties )
       
  3200         {
       
  3201         // We only handle one delivery report at a time
       
  3202         iRemoteParties = new ( ELeave )CDesCArrayFlat( 1 );
       
  3203         }
       
  3204     else
       
  3205         {
       
  3206         iRemoteParties->Reset();
       
  3207         }
       
  3208 
       
  3209     // save the items that are the same for all our events
       
  3210     iLogEvent->SetEventType( KLogMmsEventTypeUid );
       
  3211     iLogClient->GetString( iLogString, R_LOG_DIR_OUT );
       
  3212     iLogEvent->SetDirection( iLogString );
       
  3213     iLogEvent->SetDurationType( KLogDurationNone );
       
  3214     // This should never stay
       
  3215     iLogClient->GetString( iLogString, R_LOG_DEL_SENT );
       
  3216     iLogEvent->SetStatus( iLogString );
       
  3217 
       
  3218     CMsvStore* store = NULL;
       
  3219 
       
  3220     TRAP( iError, store = iServerEntry->ReadStoreL(); )
       
  3221 
       
  3222     if ( iError == KErrNone )
       
  3223         {
       
  3224         CleanupStack::PushL( store );
       
  3225         iMmsHeaders->RestoreL( *store );
       
  3226         CleanupStack::PopAndDestroy( store );
       
  3227         iLogEvent->SetDataL( iMmsHeaders->MessageId() );
       
  3228         // Use delivery time from delivery report
       
  3229         iLogEvent->SetTime( TTime( KMmsYear1970String ) +
       
  3230             TTimeIntervalMicroSeconds( iMmsHeaders->Date() * KMmsMillion ) );
       
  3231         
       
  3232         switch ( iMmsHeaders->Status() )
       
  3233             {
       
  3234             case KMmsMessageStatusRetrieved:
       
  3235             case KMmsMessageStatusForwarded: // forwarded is delivered from our point of view
       
  3236                 iDeliveryStatus = ETrue;
       
  3237                 iLogClient->GetString( iLogString, R_LOG_DEL_DONE );
       
  3238                 break;
       
  3239             case KMmsMessageStatusExpired:
       
  3240             case KMmsMessageStatusRejected:
       
  3241             case KMmsMessageStatusUnreachable:
       
  3242                 iDeliveryStatus = EFalse;
       
  3243                 iLogClient->GetString( iLogString, R_LOG_DEL_FAILED );
       
  3244                 break;
       
  3245             default:
       
  3246                 if ( !readReport )
       
  3247                     {
       
  3248                     // if status cannot be mapped, it is just "pending"
       
  3249                     // KMmsMessageStatusDeferred, KMmsMessageStatusUnrecognized, and KMmsMessageStatusIndeterminate
       
  3250                     // map to "pending" state
       
  3251                     iLogClient->GetString( iLogString, R_LOG_DEL_PENDING );
       
  3252                     }
       
  3253                 else
       
  3254                     {
       
  3255                     // read report can only have status "read" or 
       
  3256                     // "deleted without being read"
       
  3257                     // We need some string mapping for those...
       
  3258                     if ( iMmsHeaders->ReadStatus() == KMmsReadStatusRead )
       
  3259                         {
       
  3260                         // read
       
  3261                         iLogString.Copy( KLogsMsgReadText );
       
  3262                         }
       
  3263                     else
       
  3264                         {
       
  3265                         // deleted without being read
       
  3266                         // This does not change "delivered" status
       
  3267                         // But in case the delivery report has not arrived,
       
  3268                         // This ensures that the information of delivery gets stored.
       
  3269                         // If the user deleted the message without reading it,
       
  3270                         // it must have been delivered first.
       
  3271                         iLogClient->GetString( iLogString, R_LOG_DEL_DONE );
       
  3272                         }
       
  3273                     }
       
  3274                 break;
       
  3275             }
       
  3276             
       
  3277 #ifndef _NO_MMSS_LOGGING_
       
  3278         TMmsLogger::Log( _L("MmsServer delivery status code %d"), iMmsHeaders->Status() );
       
  3279         TMmsLogger::Log( _L(" - delivery status %S"), &iLogString );
       
  3280         TMmsLogger::Log( _L(" - delivery datetime:") );
       
  3281         CMmsBaseOperation::LogDateL( iLogEvent->Time() );
       
  3282 #endif
       
  3283         iLogEvent->SetStatus( iLogString );
       
  3284         if ( iMmsHeaders->ToRecipients().MdcaCount() == 0 &&
       
  3285             iMmsHeaders->Sender().Length() == 0 )
       
  3286             {
       
  3287             // No recipient, cannot log
       
  3288             // no use retrying either
       
  3289             *iRequestStatus = KRequestPending;
       
  3290             iStatus = KRequestPending;
       
  3291             SetActive();
       
  3292             User::RequestComplete( status, KErrNone );
       
  3293             return;
       
  3294             }
       
  3295         if ( !readReport )
       
  3296             {
       
  3297             iRemoteParties->AppendL( TMmsGenUtils::PureAddress(
       
  3298                 iMmsHeaders->ToRecipients().MdcaPoint( 0 ) ) );
       
  3299             }
       
  3300         else
       
  3301             {
       
  3302             // If we have a read report, the remote party is the sender
       
  3303             iRemoteParties->AppendL( TMmsGenUtils::PureAddress(
       
  3304                 iMmsHeaders->Sender() ) );
       
  3305             }
       
  3306 
       
  3307 // CMmsLog is responsible for setting our status to "KRequestPending"
       
  3308 // If the status or the entry is already "read" it must not be changed
       
  3309 // back to "delivered"
       
  3310 // CMmsLog must take care of that because it is the component that
       
  3311 // finds the corresponding entry from the log database
       
  3312         iMmsLog->StartL( *iLogEvent, *iRemoteParties, iStatus);
       
  3313         *iRequestStatus = KRequestPending;
       
  3314         SetActive();
       
  3315         }
       
  3316     else
       
  3317         {
       
  3318 #ifndef _NO_MMSS_LOGGING_
       
  3319         TMmsLogger::Log( _L("MmsServer could not access delivery report") );
       
  3320 #endif
       
  3321         // Retry later.
       
  3322         // now our error is not KErrNone, so we will reschedule
       
  3323         // in UpdateEntriesL
       
  3324         *iRequestStatus = KRequestPending;
       
  3325         iStatus = KRequestPending;
       
  3326         SetActive();
       
  3327         User::RequestComplete( status, iError );
       
  3328         }
       
  3329 
       
  3330     }
       
  3331     
       
  3332 // ---------------------------------------------------------
       
  3333 // CMmsServerMtm::PruneDuplicateNotificationsL
       
  3334 // 
       
  3335 // ---------------------------------------------------------
       
  3336 //
       
  3337 TBool CMmsServerMtm::PruneDuplicateNotificationsL( TMsvId aParent, CMmsHeaders& aNotification )
       
  3338     {
       
  3339 #ifndef _NO_MMSS_LOGGING_
       
  3340     TMmsLogger::Log( _L("MmsServer Pruning duplicate notifications") );
       
  3341 #endif
       
  3342     TInt error = KErrNone;
       
  3343     TBool pruned = EFalse;
       
  3344     TMsvId mmsFolder = FindMMSFolderL();
       
  3345     
       
  3346     if ( aParent == KMsvNullIndexEntryId )
       
  3347         {
       
  3348 #ifndef _NO_MMSS_LOGGING_
       
  3349         TMmsLogger::Log( _L("- no proper parent") );
       
  3350 #endif
       
  3351         return EFalse;
       
  3352         }
       
  3353 
       
  3354     error = iServerEntry->SetEntry( aParent );
       
  3355     if ( error != KErrNone )
       
  3356         {
       
  3357         // cannot access parent, cannot prune.
       
  3358 #ifndef _NO_MMSS_LOGGING_
       
  3359         TMmsLogger::Log( _L("- cannot access notification parent, error %d "), error );
       
  3360 #endif
       
  3361         return EFalse;
       
  3362         }
       
  3363 
       
  3364     // show invisible entries
       
  3365     TMsvSelectionOrdering ordering =
       
  3366         TMsvSelectionOrdering( KMsvNoGrouping, EMsvSortByNone, ETrue );
       
  3367     iServerEntry->SetSort( ordering );
       
  3368 
       
  3369     CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection; 
       
  3370     CleanupStack::PushL( selection );
       
  3371     if ( aParent == mmsFolder )
       
  3372         {
       
  3373         error = iServerEntry->GetChildrenWithType( KUidMsvMessageEntry, *selection );
       
  3374 #ifndef _NO_MMSS_LOGGING_
       
  3375         TMmsLogger::Log( _L("- from MMS Folder") );
       
  3376 #endif
       
  3377         }
       
  3378     else
       
  3379         {
       
  3380         error = iServerEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *selection );
       
  3381 #ifndef _NO_MMSS_LOGGING_
       
  3382         if ( aParent == KMsvGlobalInBoxIndexEntryIdValue )
       
  3383             {
       
  3384             TMmsLogger::Log( _L("- from Inbox") );
       
  3385             }
       
  3386         else
       
  3387             {
       
  3388             TMmsLogger::Log( _L("- from mmbox folder") );
       
  3389             }
       
  3390 #endif
       
  3391         }
       
  3392 
       
  3393     TInt count = selection->Count();
       
  3394 #ifndef _NO_MMSS_LOGGING_
       
  3395     TMmsLogger::Log( _L("- %d notifications on disk"), count );
       
  3396 #endif
       
  3397     if ( error != KErrNone || count == 0 )
       
  3398         {
       
  3399         // cannot check or no old notifications found, anything goes
       
  3400         CleanupStack::PopAndDestroy( selection ); // selection
       
  3401         return EFalse;
       
  3402         }
       
  3403 
       
  3404     TInt i;
       
  3405     CMmsHeaders* notification = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
       
  3406     CleanupStack::PushL( notification );
       
  3407     CMsvStore* store = NULL;
       
  3408     for ( i = count; i > 0 && !pruned; i-- )
       
  3409         {
       
  3410         error = iServerEntry->SetEntry( selection->At( i - 1 ) );
       
  3411         if ( error != KErrNone )
       
  3412             {
       
  3413 #ifndef _NO_MMSS_LOGGING_
       
  3414             TMmsLogger::Log( _L("- cannot access notification") );
       
  3415 #endif
       
  3416             // cannot handle this entry.
       
  3417             continue;
       
  3418             }
       
  3419         if ( ( ( iServerEntry->Entry().iMtmData1 != 0 ) &&
       
  3420             ( ( iServerEntry->Entry().iMtmData1 & KMmsMessageTypeMask ) !=
       
  3421             KMmsMessageMNotificationInd ) ) ||
       
  3422             ( iServerEntry->Entry().iMtmData2 & KMmsNotificationBinary ) ) 
       
  3423             {
       
  3424 #ifndef _NO_MMSS_LOGGING_
       
  3425             TMmsLogger::Log( _L("- not a notification") );
       
  3426 #endif
       
  3427             continue;
       
  3428             }
       
  3429 
       
  3430         // binary notifications (empty entries) were already handled, so we can delete the rest
       
  3431         if ( iServerEntry->Entry().iMtmData1 == 0 )
       
  3432             {
       
  3433             // remove garbage.
       
  3434             error = iServerEntry->SetEntry( aParent );
       
  3435             if ( error == KErrNone )
       
  3436                 {
       
  3437                 // never mind the error - we are just doing our best
       
  3438                 iServerEntry->DeleteEntry( selection->At( i - 1 ) );
       
  3439                 }
       
  3440             continue;
       
  3441             }
       
  3442 
       
  3443         error = KErrNone;
       
  3444         TRAP( error, 
       
  3445             {
       
  3446             store = iServerEntry->ReadStoreL();
       
  3447             CleanupStack::PushL( store );
       
  3448             notification->RestoreL( *store );
       
  3449             CleanupStack::PopAndDestroy( store ); // store
       
  3450             })
       
  3451         store = NULL;
       
  3452 
       
  3453         if ( error != KErrNone )
       
  3454             {
       
  3455 #ifndef _NO_MMSS_LOGGING_
       
  3456             TMmsLogger::Log( _L("- cannot access notification") );
       
  3457 #endif
       
  3458             // cannot handle this entry.
       
  3459             continue;
       
  3460             }
       
  3461 
       
  3462         // content location is used to identify notifications
       
  3463         // referring to the same message.
       
  3464         // Content location is the only information given back to
       
  3465         // MMSC when fetching a message, therefore it must be unique
       
  3466         if ( notification->ContentLocation().Compare( aNotification.ContentLocation() ) == 0 )
       
  3467             {
       
  3468             // Identical. This probably means that we have not sent a response yet,
       
  3469             // and MMSC has sent us a new notification.
       
  3470 
       
  3471 #ifndef _NO_MMSS_LOGGING_
       
  3472             TMmsLogger::Log( _L("- content locations match") );
       
  3473 #endif
       
  3474             pruned = ETrue;
       
  3475             }
       
  3476         }
       
  3477 
       
  3478     CleanupStack::PopAndDestroy( notification );
       
  3479     CleanupStack::PopAndDestroy( selection );
       
  3480     error = iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  3481 
       
  3482     return pruned;
       
  3483     }
       
  3484 
       
  3485 // ---------------------------------------------------------
       
  3486 // CMmsServerMtm::CheckNotificationsL
       
  3487 // 
       
  3488 // ---------------------------------------------------------
       
  3489 //
       
  3490 void CMmsServerMtm::CheckNotificationsL( CMsvEntrySelection& aSelection )
       
  3491     {
       
  3492     TInt error = KErrNone;
       
  3493     TMsvId parent = KMsvNullIndexEntryId;
       
  3494     TMsvId mmsFolder = FindMMSFolderL();
       
  3495     if ( mmsFolder == KMsvNullIndexEntryId )
       
  3496         {
       
  3497         // no folder...
       
  3498         return;
       
  3499         }
       
  3500     
       
  3501     TInt i;
       
  3502     
       
  3503     // Don't mix notifications from mms folder and inbox,
       
  3504     // in debug mode Symbian scheduler panics.
       
  3505     if ( aSelection.Count() > 0 )
       
  3506         {
       
  3507         i = aSelection.Count() - 1;
       
  3508         while ( i >= 0 && parent == KMsvNullIndexEntryId )
       
  3509             {
       
  3510             error = iServerEntry->SetEntry( aSelection.At( 0 ) );
       
  3511             if ( error == KErrNone )
       
  3512                 {
       
  3513                 parent = iServerEntry->Entry().Parent();
       
  3514                 }
       
  3515             else if ( error == KErrNotFound )
       
  3516                 {
       
  3517                 // The entry has disappeared already.
       
  3518                 aSelection.Delete( i );
       
  3519                 }
       
  3520             else
       
  3521                 {
       
  3522                 // keep LINT happy
       
  3523                 }
       
  3524             i--;    
       
  3525             }
       
  3526         }
       
  3527     
       
  3528     if ( parent == KMsvNullIndexEntryId ) 
       
  3529         {
       
  3530         parent = mmsFolder;
       
  3531         }
       
  3532 
       
  3533 #ifndef _NO_MMSS_LOGGING_
       
  3534     TMmsLogger::Log( _L("CheckNotificationsL, got %d entries"), aSelection.Count() );
       
  3535 #endif
       
  3536 
       
  3537     error = iServerEntry->SetEntry( parent );
       
  3538     User::LeaveIfError( error );
       
  3539     
       
  3540     // If no notifications input find notifications from mms folder
       
  3541     if ( parent == mmsFolder && aSelection.Count() == 0 )
       
  3542         {
       
  3543         error = iServerEntry->GetChildrenWithType( KUidMsvMessageEntry, aSelection );
       
  3544 #ifndef _NO_MMSS_LOGGING_
       
  3545         TMmsLogger::Log( _L("Notifications found in mms folder %d "), aSelection.Count() );
       
  3546 #endif
       
  3547         if ( error != KErrNone )
       
  3548             {
       
  3549             aSelection.Reset(); // make sure we return no garbage
       
  3550             User::Leave( error );
       
  3551             }
       
  3552         }
       
  3553     
       
  3554     // notifications in inbox
       
  3555     // If we have a selection, we don't generate new ones,
       
  3556     // An empty selection only lists notifications from MMS folder, we cannot
       
  3557     // touch inbox stuff otherwise.
       
  3558     // MMS Client MTM lists notifications from inbox when mode is changed
       
  3559     // from manual to automatic.
       
  3560     
       
  3561     if ( parent == KMsvGlobalInBoxIndexEntryId )
       
  3562         {
       
  3563 #ifndef _NO_MMSS_LOGGING_
       
  3564         TMmsLogger::Log( _L("Notifications found in inbox %d "), aSelection.Count() );
       
  3565 #endif
       
  3566         TInt j;
       
  3567         for ( j = aSelection.Count() - 1; j >= 0; j-- )
       
  3568             {
       
  3569             error = iServerEntry->SetEntry( aSelection.At( j ) );
       
  3570             TMsvEntry entry;
       
  3571             if ( error == KErrNone )
       
  3572                 {
       
  3573                 entry = iServerEntry->Entry();
       
  3574                 }
       
  3575 
       
  3576             // Drop notification, if operationForbidden flag is on OR
       
  3577             // if messageexpired flag is on OR
       
  3578             // if notification is not stored in mmbox and forward operation has been succussfull OR
       
  3579             // if notification is deleted succuessfully from mmbox OR 
       
  3580             // if notification is fetched successfully from mmbox.
       
  3581             // Or if notification cannot be accessed (used by someone else)
       
  3582             if ( error != KErrNone ||
       
  3583                 entry.iMtmData2 & KMmsNewOperationForbidden ||
       
  3584                 entry.iMtmData2 & KMmsMessageExpired ||
       
  3585                 ( entry.iMtmData2 & KMmsOperationFinished &&
       
  3586                 !( entry.iMtmData2 & KMmsOperationResult) &&
       
  3587                 !(entry.iMtmData2 & KMmsStoredInMMBox) ) )
       
  3588                 {
       
  3589 #ifndef _NO_MMSS_LOGGING_
       
  3590                 TMmsLogger::Log( _L(" Dropped " ));
       
  3591                 aSelection.Delete( j );
       
  3592 #endif
       
  3593                 }
       
  3594             else
       
  3595                 {
       
  3596                 // mark this that others can't start do an operation
       
  3597                 entry.iMtmData2 |= KMmsNewOperationForbidden; 
       
  3598             
       
  3599                 // readonly is needed to set EFalse for scheduling
       
  3600                 entry.SetReadOnly( EFalse ); 
       
  3601                 iServerEntry->ChangeEntry( entry );
       
  3602                 // We keep this entry in our selection
       
  3603                 }
       
  3604             }
       
  3605         aSelection.Compress();
       
  3606         }
       
  3607         
       
  3608     error = iServerEntry->SetEntry( parent );
       
  3609 
       
  3610     // Check the list and see what we got.
       
  3611     // The list may contain both notifications and delivery reports
       
  3612     
       
  3613     TInt count = aSelection.Count();
       
  3614 #ifndef _NO_MMSS_LOGGING_
       
  3615     TMmsLogger::Log( _L("Found %d entries altogether"), count );
       
  3616 #endif
       
  3617     TMsvEntry tEntry;
       
  3618     CMsvEntrySelection* thisNotification = NULL;
       
  3619     TTime now;
       
  3620     TTime entryTime;
       
  3621     
       
  3622     for ( i = count; i > 0; i-- )
       
  3623         {
       
  3624         error = iServerEntry->SetEntry( aSelection.At( i - 1 ) );
       
  3625         if ( error == KErrNoMemory )
       
  3626             {
       
  3627             User::Leave( error );
       
  3628             }
       
  3629         else if ( error != KErrNone )
       
  3630             {
       
  3631             continue;
       
  3632             }
       
  3633         else
       
  3634             {
       
  3635             // keep LINT happy
       
  3636             }
       
  3637         tEntry = iServerEntry->Entry();
       
  3638         parent = tEntry.Parent();
       
  3639         // We keep only notifications - the rest are removed from the list.
       
  3640         // If we are doing garbage collection, all non-notifications are
       
  3641         // deleted from the disk (because they will never expire).
       
  3642         // See if a notification or dummy entry
       
  3643         if ( iServerEntry->Entry().iMtmData2 & KMmsNotificationBinary &&
       
  3644             iCurrentCommand == EMmsGarbageCollection )
       
  3645             {
       
  3646             // get rid of these as these are empty
       
  3647 #ifndef _NO_MMSS_LOGGING_
       
  3648             TMmsLogger::Log( _L("- dummy entry - deleting"));
       
  3649 #endif
       
  3650             error = iServerEntry->SetEntry( parent );
       
  3651             if ( error == KErrNone )
       
  3652                 {
       
  3653                 iServerEntry->DeleteEntry( aSelection.At( i - 1 ) );
       
  3654                 }
       
  3655             aSelection.Delete( i - 1 );
       
  3656             }
       
  3657         else if ( ( tEntry.iMtmData1 & KMmsMessageTypeMask ) != KMmsMessageMNotificationInd )
       
  3658             {
       
  3659 #ifndef _NO_MMSS_LOGGING_
       
  3660             TMmsLogger::Log( _L("- not a notification"));
       
  3661 #endif
       
  3662             if ( iCurrentCommand == EMmsGarbageCollection )
       
  3663                 {
       
  3664                 // If we are doing garbage collection, these are deleted, too
       
  3665                 // If any delivery reports or other non-notification stuff
       
  3666                 // is around at garbage collection time, it has become garbage.
       
  3667                 
       
  3668                 // Garbage collection is called with MMS Service, not with
       
  3669                 // local service, so it means that garbage collection cannot
       
  3670                 // be called when some other operation is ongoing.
       
  3671                 // It should not be possible to delete an entry that is being
       
  3672                 // handled already because access to MMS Server MTM is sequential
       
  3673                 
       
  3674                 // However, a delivery report or read report might just have been
       
  3675                 // scheduled for handling. Check that they won't get deleted too soon
       
  3676                 
       
  3677                 thisNotification = new( ELeave ) CMsvEntrySelection;
       
  3678                 CleanupStack::PushL( thisNotification );
       
  3679                 thisNotification->AppendL( aSelection.At( i - 1 ) );
       
  3680                 iScheduleSend->CheckScheduleL( *thisNotification );
       
  3681                 CleanupStack::PopAndDestroy( thisNotification );
       
  3682                 thisNotification = NULL;
       
  3683 
       
  3684                 TBool alreadyScheduled = EFalse;
       
  3685                 
       
  3686                 if ( iServerEntry->Entry().Scheduled() )
       
  3687                     {
       
  3688                     // Already scheduled - check, if schedule is valid
       
  3689                     // Leave the schedule, if it is in the future - but not too much
       
  3690                     now.UniversalTime();
       
  3691                     now += TTimeIntervalSeconds( KMmsScheduleDelay );
       
  3692                     entryTime = iServerEntry->Entry().iDate;
       
  3693                     if ( ( ( entryTime - TTimeIntervalHours( KMmsSanityInterval ) ) <= now ) &&
       
  3694                         ( entryTime > now ) )
       
  3695                         {
       
  3696                         // scheduled in the future, we don't touch it
       
  3697                         alreadyScheduled = ETrue;
       
  3698 #ifndef _NO_MMSS_LOGGING_
       
  3699                         TMmsLogger::Log( _L("- already scheduled"));
       
  3700 #endif
       
  3701                         }
       
  3702                     }
       
  3703                 
       
  3704                 error = iServerEntry->SetEntry( parent );
       
  3705                 if ( error == KErrNone && !alreadyScheduled )
       
  3706                     {
       
  3707                     // we delete extra entries - but if they seem to have
       
  3708                     // legal schedule we leave them, the scheduling will
       
  3709                     // handle them in due time
       
  3710                     iServerEntry->DeleteEntry( aSelection.At( i - 1 ) );
       
  3711                     }
       
  3712                 }
       
  3713             // We always clear the non-notifications from our list
       
  3714             // Either they were already legally scheduled and were left alone
       
  3715             // or they were gagbage and were deleted
       
  3716             aSelection.Delete( i - 1 );
       
  3717             }
       
  3718         else
       
  3719             {
       
  3720             // Check if scheduled
       
  3721 
       
  3722             thisNotification = new( ELeave ) CMsvEntrySelection;
       
  3723             CleanupStack::PushL( thisNotification );
       
  3724             thisNotification->AppendL( aSelection.At( i - 1 ) );
       
  3725             if ( iCommand != EMmsReceiveForced )
       
  3726                 {
       
  3727                 iScheduleSend->CheckScheduleL( *thisNotification );
       
  3728                 }
       
  3729             else
       
  3730                 // if we do forced fetch, we clean up old schedules first
       
  3731                 {
       
  3732 #ifndef _NO_MMSS_LOGGING_
       
  3733                 TMmsLogger::Log( _L("- cleaning schedules"));
       
  3734 #endif
       
  3735                 CleanSchedulesL( *thisNotification );
       
  3736                 tEntry = iServerEntry->Entry();
       
  3737                 }
       
  3738 
       
  3739             if ( iServerEntry->Entry().Scheduled() )
       
  3740                 {
       
  3741                 // Already scheduled - check, if schedule is valid
       
  3742                 // Reschedule this, if it was scheduled in the past
       
  3743                 // The entry is left into the selection list.
       
  3744                 // If the list is rescheduled, this entry will
       
  3745                 // be rescheduled to a later time.
       
  3746                 // Leave the schedule, if it is in the future - but not too much
       
  3747                 now.UniversalTime();
       
  3748                 now += TTimeIntervalSeconds( KMmsScheduleDelay );
       
  3749                 entryTime = iServerEntry->Entry().iDate;
       
  3750                 if ( ( ( entryTime - TTimeIntervalHours( KMmsSanityInterval ) ) <= now ) &&
       
  3751                                 ( entryTime > now ) )
       
  3752                     {
       
  3753                     // scheduled in the future, we don't touch it
       
  3754 #ifndef _NO_MMSS_LOGGING_
       
  3755                     TMmsLogger::Log( _L("- already scheduled"));
       
  3756 #endif
       
  3757                     aSelection.Delete( i - 1 );
       
  3758                     }
       
  3759                 }
       
  3760             else
       
  3761                 {
       
  3762                 // Check expiration
       
  3763                 CMsvStore * store = NULL;
       
  3764                 store = iServerEntry->ReadStoreL();
       
  3765                 CleanupStack::PushL( store );
       
  3766                 iMmsHeaders->RestoreL( *store );
       
  3767                 CleanupStack::PopAndDestroy( store );
       
  3768                 TTime now;
       
  3769                 now.UniversalTime();
       
  3770 #ifndef _NO_MMSS_LOGGING_
       
  3771                 TMmsLogger::Log( _L("MMSserver checking notifications") );
       
  3772                 TMmsLogger::Log( _L("MMS terminal universal datetime: ") );
       
  3773                 CMmsBaseOperation::LogDateL( now );
       
  3774                 TMmsLogger::Log( _L("MMS message expiry datetime:") );
       
  3775                 CMmsBaseOperation::LogNetworkFormatDateL( iMmsHeaders->ExpiryDate() );
       
  3776 #endif
       
  3777                 if ( ( ( iMmsHeaders->ExpiryDate() + iMmsSettings->ExpiryOvershoot() ) *
       
  3778                     KMmsMillion ) < now.MicroSecondsFrom( TTime( KMmsYear1970String ) ).Int64() )
       
  3779                     {
       
  3780                     // expired
       
  3781                     // remove schedule, 
       
  3782                     iScheduleSend->DeleteScheduleL( *thisNotification );
       
  3783 
       
  3784                     // if the entry is in inbox or in mmbox folder, let it go                   
       
  3785                     if ( parent == KMsvGlobalInBoxIndexEntryIdValue  ||
       
  3786                          parent == iMmsSettings->MMBoxFolder() )
       
  3787                         {
       
  3788                         tEntry.SetReadOnly( ETrue );
       
  3789                         // not forbidden for a new operation
       
  3790                         tEntry.iMtmData2 &= ~KMmsNewOperationForbidden;
       
  3791                         iServerEntry->ChangeEntry( tEntry );
       
  3792 
       
  3793                         }
       
  3794                     else // delete the whole entry if it is in mms folder
       
  3795                         {
       
  3796                         error = iServerEntry->SetEntry( parent );
       
  3797                         if ( error == KErrNone )
       
  3798                             {
       
  3799                             iServerEntry->DeleteEntry( aSelection.At( i - 1 ) );
       
  3800 #ifndef _NO_MMSS_LOGGING_
       
  3801                             TMmsLogger::Log( _L("- whole entry deleted"));
       
  3802 #endif
       
  3803                             }
       
  3804                         }
       
  3805 #ifndef _NO_MMSS_LOGGING_
       
  3806                     TMmsLogger::Log( _L("- already expired"));
       
  3807 #endif
       
  3808                     aSelection.Delete( i - 1 );
       
  3809                     }
       
  3810                 }
       
  3811             CleanupStack::PopAndDestroy( thisNotification );
       
  3812             thisNotification = NULL;
       
  3813             }
       
  3814         }
       
  3815     aSelection.Compress();
       
  3816     
       
  3817 #ifndef _NO_MMSS_LOGGING_
       
  3818     TMmsLogger::Log( _L("CheckNotificationsL, %d entries left"), aSelection.Count() );
       
  3819 #endif
       
  3820 
       
  3821     }
       
  3822 
       
  3823 // ---------------------------------------------------------
       
  3824 // CMmsServerMtm::CreateNotificationsL()
       
  3825 // 
       
  3826 // ---------------------------------------------------------
       
  3827 //
       
  3828 void CMmsServerMtm::CreateNotificationsL()
       
  3829     {
       
  3830     // This function is for testing and message variation
       
  3831 
       
  3832     TInt err = KErrNone;
       
  3833     TInt i;
       
  3834     TInt count = 0;
       
  3835     TUint size = 0;
       
  3836     // Include old notifications into the selection
       
  3837     // Except when doing message generation at boot time -
       
  3838     // Then only new notifications are handled
       
  3839     if ( iCurrentCommand != EMmsMessageGeneration )
       
  3840         {
       
  3841         CheckNotificationsL( *iMsvSelection );
       
  3842         }
       
  3843     count = iMsvSelection->Count();
       
  3844 
       
  3845     // If there are notifications to be handled, we don't
       
  3846     // create new ones, because new notification creation
       
  3847     // should be used for testing only
       
  3848     if ( !iMmsSettings->LocalMode() && count > 0 )
       
  3849         {
       
  3850 #ifndef _NO_MMSS_LOGGING_
       
  3851         TMmsLogger::Log( _L("CreateNotificationsL - Global mode") );
       
  3852         TMmsLogger::Log( _L("- %d old notifications, not generating new ones"), count );
       
  3853 #endif
       
  3854         return;
       
  3855         }
       
  3856         
       
  3857     RFs fs; // We need a separate session to be able to set the session path
       
  3858     err = fs.Connect();
       
  3859     if ( err != KErrNone )
       
  3860         {
       
  3861         return;
       
  3862         }
       
  3863     CleanupClosePushL( fs );
       
  3864 
       
  3865     HBufC8* bufferPointer = HBufC8::NewL( KMaxFileName );
       
  3866     CleanupStack::PushL( bufferPointer );
       
  3867     TPtr8 buffer = bufferPointer->Des();
       
  3868 
       
  3869     CDir* fileList = NULL;
       
  3870 
       
  3871     // create notifications for local messages:
       
  3872     if ( iMmsSettings->LocalMode() )
       
  3873         {
       
  3874 #ifndef _NO_MMSS_LOGGING_
       
  3875         TMmsLogger::Log( _L("CreateNotificationsL - Local mode"));
       
  3876 #endif
       
  3877         TEntry* entry = new( ELeave ) TEntry; // allocated from heap to save stack space
       
  3878         CleanupStack::PushL( entry );
       
  3879         HBufC* filename = HBufC::NewL( iMmsSettings->LocalModeIn().Length() );
       
  3880         CleanupStack::PushL( filename );
       
  3881         TPtr fileNamePtr = filename->Des();
       
  3882         fileNamePtr.Copy( iMmsSettings->LocalModeIn() );
       
  3883 #ifndef _NO_MMSS_LOGGING_
       
  3884         TMmsLogger::Log( _L("local mode dir %S "), &fileNamePtr );
       
  3885 #endif
       
  3886         err = fs.SetSessionPath( fileNamePtr );
       
  3887 #ifndef _NO_MMSS_LOGGING_
       
  3888         TMmsLogger::Log( _L("set session path returned: %d"), err );
       
  3889         HBufC* temp = HBufC::NewL( KMaxPath );
       
  3890         CleanupStack::PushL( temp );
       
  3891         TPtr tempPtr = temp->Des();
       
  3892         fs.SessionPath( tempPtr );
       
  3893         TMmsLogger::Log( _L("Session path: %S"), &tempPtr );
       
  3894         CleanupStack::PopAndDestroy( temp );
       
  3895         temp = NULL;
       
  3896 #endif
       
  3897         err = fs.Entry( fileNamePtr, *entry );
       
  3898 #ifndef _NO_MMSS_LOGGING_
       
  3899         TMmsLogger::Log( _L("get path properties returned: %d"), err );
       
  3900 #endif
       
  3901         if ( err == KErrNone )
       
  3902             {
       
  3903             TFindFile* finder = new( ELeave ) TFindFile( fs ); // allocated from heap to save stack space
       
  3904             CleanupStack::PushL( finder );
       
  3905             _LIT( KWild, "*" );
       
  3906 
       
  3907             err = finder->FindWildByPath( KWild, &fileNamePtr, fileList );
       
  3908 #ifndef _NO_MMSS_LOGGING_
       
  3909             TMmsLogger::Log( _L("find files returned: %d"), err );
       
  3910 #endif
       
  3911             CleanupStack::PopAndDestroy( finder );
       
  3912             
       
  3913             if ( fileList )
       
  3914                 {
       
  3915                 CleanupStack::PushL( fileList );
       
  3916                 }
       
  3917 
       
  3918             if ( err == KErrNone )
       
  3919                 {
       
  3920                 count = fileList->Count();
       
  3921                 }
       
  3922             else
       
  3923                 {
       
  3924                 count = 0;
       
  3925                 }
       
  3926             }
       
  3927 
       
  3928 #ifndef _NO_MMSS_LOGGING_
       
  3929         TMmsLogger::Log( _L("found %d files in %S"), count, &fileNamePtr );
       
  3930 #endif
       
  3931         for (i = 0; i < count; i++ )
       
  3932             {
       
  3933             iParse.Set( ( ( *fileList )[i] ).iName, &fileNamePtr, NULL );
       
  3934             buffer.Copy( iParse.FullName() );
       
  3935 
       
  3936             size = fs.Entry( iParse.FullName(), *entry );
       
  3937             size = entry->iSize;
       
  3938 
       
  3939             iNotification = KMsvNullIndexEntryId;
       
  3940 
       
  3941 #ifndef _NO_MMSS_LOGGING_
       
  3942             TMmsLogger::Log( _L("notification size %d"), size );
       
  3943 #endif
       
  3944             if ( size > 0 )
       
  3945                 {
       
  3946                 if ( !iEncodeBuffer )
       
  3947                     {
       
  3948                     iEncodeBuffer = CBufFlat::NewL( 0x400 );
       
  3949                     }
       
  3950                 else
       
  3951                     {
       
  3952                     iEncodeBuffer->Reset();
       
  3953                     }
       
  3954 
       
  3955                 CreateNotificationL( buffer, size );
       
  3956 #ifndef _NO_MMSS_LOGGING_
       
  3957                 TMmsLogger::Log( _L("notification created") );
       
  3958 #endif
       
  3959 
       
  3960                 DecodePushedMessageL();
       
  3961 #ifndef _NO_MMSS_LOGGING_
       
  3962                 TMmsLogger::Log( _L("notification decoded") );
       
  3963 #endif
       
  3964                 delete iEncodeBuffer;
       
  3965                 iEncodeBuffer = NULL;
       
  3966                 }
       
  3967             else
       
  3968                 {
       
  3969                 fs.Delete( iParse.FullName() );
       
  3970                 }
       
  3971         
       
  3972             if ( iNotification != KMsvNullIndexEntryId )
       
  3973                 {
       
  3974                 iMsvSelection->AppendL( iNotification );
       
  3975                 }
       
  3976 
       
  3977             }
       
  3978         if ( fileList )
       
  3979             {
       
  3980             CleanupStack::PopAndDestroy( fileList );
       
  3981             }
       
  3982             
       
  3983         CleanupStack::PopAndDestroy( filename );
       
  3984         CleanupStack::PopAndDestroy( entry );
       
  3985         }
       
  3986 
       
  3987     CleanupStack::PopAndDestroy( bufferPointer );
       
  3988     CleanupStack::PopAndDestroy( &fs ); // close fs
       
  3989     iServerEntry->SetEntry( iServiceEntryId );
       
  3990 
       
  3991 #ifndef _NO_MMSS_LOGGING_
       
  3992     TMmsLogger::Log( _L("CreateNotificationsL - %d notifications"), iMsvSelection->Count() );
       
  3993 #endif
       
  3994     }
       
  3995 
       
  3996 // ---------------------------------------------------------
       
  3997 // CMmsServerMtm::CreateNotificationL()
       
  3998 //
       
  3999 // ---------------------------------------------------------
       
  4000 //
       
  4001 void CMmsServerMtm::CreateNotificationL( TDesC8& aUrl, TInt aSize )
       
  4002     {
       
  4003     // for test purposes aUrl will contain the filename.
       
  4004 
       
  4005     // Reset sets the default encapsulation version
       
  4006     // The default version has been set from MmsSettings in NewL
       
  4007     iMmsHeaders->Reset();
       
  4008 
       
  4009     // construct the notification into iMmsHeaders, and call encode
       
  4010 
       
  4011     iMmsHeaders->SetMessageType( KMmsMessageTypeMNotificationInd );
       
  4012 
       
  4013     TTime currentTime;
       
  4014     currentTime.UniversalTime();
       
  4015     currentTime.Int64();
       
  4016 
       
  4017     TBufC8<KMMSMAXTIDLENGTH> tid;
       
  4018     tid.Des().NumUC( currentTime.Int64(), EHex );
       
  4019     iMmsHeaders->SetTidL( tid );
       
  4020 
       
  4021     iMmsHeaders->SetMessageClass( EMmsClassPersonal );
       
  4022     iMmsHeaders->SetMessageSize( aSize );
       
  4023     const TInt KTenHours = 10 * 60 * 60; // 10 hours relative expiry
       
  4024     iMmsHeaders->SetExpiryInterval( KTenHours );
       
  4025     iMmsHeaders->SetContentLocationL( aUrl );
       
  4026  
       
  4027     CMmsEncode* encoder = CMmsEncode::NewL( iFs );
       
  4028     CleanupStack::PushL( encoder );
       
  4029     encoder->EncodeHeadersL( *iMmsHeaders, *iEncodeBuffer );
       
  4030     CleanupStack::PopAndDestroy( encoder ); // encoder
       
  4031     
       
  4032     }
       
  4033 
       
  4034 // ---------------------------------------------------------
       
  4035 // CMmsServerMtm::GarbageCollectionL
       
  4036 // 
       
  4037 // ---------------------------------------------------------
       
  4038 //
       
  4039 void CMmsServerMtm::GarbageCollectionL()
       
  4040     {
       
  4041 #ifndef _NO_MMSS_LOGGING_
       
  4042     TMmsLogger::Log( _L("MMSServer doing garbage collection") );
       
  4043 #endif
       
  4044 
       
  4045     // are we in offline mode...
       
  4046     // We use CMmsSendOperation to allow change in the name of the
       
  4047     // base opeation class. The function is in the base class anyway.
       
  4048     if ( !CMmsSendOperation::NetworkOperationsAllowed() )
       
  4049         {
       
  4050         // not allowed to send or receive anything
       
  4051         User::Leave( KMmsErrorOfflineMode );
       
  4052         }
       
  4053         
       
  4054     // MMS watcher sends us reason codes with garbage collection parameters.
       
  4055     // paramPack().iReasonFlags will contain the reason flags.
       
  4056     // paramPack().iMediaUnavailableTime tells when the memory card was removed
       
  4057     TMMSGarbageCollectionParameters param;
       
  4058     TPckgC<TMMSGarbageCollectionParameters> paramPack( param );
       
  4059     paramPack.Set( iParameter );
       
  4060     
       
  4061 #ifndef _NO_MMSS_LOGGING_
       
  4062     TMmsLogger::Log( _L("- reason code:") );
       
  4063     if ( paramPack().iReasonFlags & KMmsReasonBoot )
       
  4064         {
       
  4065         TMmsLogger::Log( _L(" -- Boot") );
       
  4066         }
       
  4067     if ( paramPack().iReasonFlags & KMmsReasonMessageStoreChanged )
       
  4068         {
       
  4069         TMmsLogger::Log( _L(" -- MessageStoreChanged") );
       
  4070         }
       
  4071     if ( paramPack().iReasonFlags & KMmsReasonNetworkAllowed )
       
  4072         {
       
  4073         TMmsLogger::Log( _L(" -- Network operations allowed") );
       
  4074         }
       
  4075     if ( paramPack().iReasonFlags & KMmsReasonBackupEnded )
       
  4076         {
       
  4077         TMmsLogger::Log( _L(" -- Backup ended") );
       
  4078         }
       
  4079     if ( paramPack().iReasonFlags & KMmsReasonHotswap )
       
  4080         {
       
  4081         TMmsLogger::Log( _L(" -- Hotswap") );
       
  4082         }
       
  4083     if ( paramPack().iReasonFlags & KMmsReasonEnvironmentTimeChanged )
       
  4084         {
       
  4085         TMmsLogger::Log( _L(" -- Environment time change") );
       
  4086         }
       
  4087 #endif
       
  4088 
       
  4089     //
       
  4090     // Forward entries left in outbox
       
  4091     //
       
  4092     GcOutBoxNotificationsL();
       
  4093     
       
  4094     //
       
  4095     // Message entries left in outbox
       
  4096     //
       
  4097     GcOutBoxMessagesL();
       
  4098     
       
  4099     //
       
  4100     // Notifications in MMSFolder (automatic fetch)
       
  4101     //
       
  4102     GcMmsFolderNotificationsL();
       
  4103     
       
  4104     //
       
  4105     // Notifications from inbox
       
  4106     //
       
  4107     GcInboxNotifications();
       
  4108 
       
  4109     //
       
  4110     // Notifications in mmbox folder    
       
  4111     //
       
  4112     GcMmboxFolderNotifications();
       
  4113         
       
  4114     }
       
  4115 
       
  4116 // ---------------------------------------------------------
       
  4117 // CMmsServerMtm::CleanSchedulesL
       
  4118 // 
       
  4119 // ---------------------------------------------------------
       
  4120 //
       
  4121 void CMmsServerMtm::CleanSchedulesL( CMsvEntrySelection& aSelection )
       
  4122     {
       
  4123     // delete old schedules and reset scheduled entry.
       
  4124     // we trap each entry separately, so that we can clean as
       
  4125     // many as possible even if there are errors
       
  4126 
       
  4127     TMsvId oldEntry = iServerEntry->Entry().Id();
       
  4128     TInt i;
       
  4129     CMsvEntrySelection* thisNotification = new( ELeave ) CMsvEntrySelection;
       
  4130     CleanupStack::PushL( thisNotification );
       
  4131     TInt error = KErrNone;
       
  4132 
       
  4133     for ( i = 0; i < aSelection.Count(); i++ )
       
  4134         {
       
  4135         TRAP ( error,
       
  4136             {
       
  4137             error = iServerEntry->SetEntry( aSelection.At( i ) );
       
  4138             if ( error == KErrNone )
       
  4139                 {
       
  4140                 CMmsScheduledEntry* mmsScheduledEntry =
       
  4141                     CMmsScheduledEntry::NewL( iServerEntry->Entry() );
       
  4142                 CleanupStack::PushL( mmsScheduledEntry );
       
  4143                 thisNotification->Reset();
       
  4144                 thisNotification->AppendL( aSelection.At( i ) );
       
  4145                 iScheduleSend->DeleteScheduleL( *thisNotification );
       
  4146 
       
  4147                 CMsvStore* store = NULL;
       
  4148                 store = iServerEntry->EditStoreL();
       
  4149                 CleanupStack::PushL( store );
       
  4150                 // We clean up the old scheduled entry data
       
  4151                 // by storing a new clean scheduled entry
       
  4152                 mmsScheduledEntry->StoreL( *store );
       
  4153                 store->CommitL();
       
  4154 
       
  4155                 CleanupStack::PopAndDestroy( store );
       
  4156                 CleanupStack::PopAndDestroy( mmsScheduledEntry );
       
  4157                 }
       
  4158             }
       
  4159             );
       
  4160         }
       
  4161     CleanupStack::PopAndDestroy( thisNotification );
       
  4162     // restore the entry we were pointing at
       
  4163     // if this fails, something is seriously wrong. We did not delete anything.
       
  4164     iServerEntry->SetEntry( oldEntry );
       
  4165 
       
  4166     }
       
  4167 
       
  4168 // ---------------------------------------------------------
       
  4169 // CMmsServerMtm::FindMMSFolderL
       
  4170 // 
       
  4171 // ---------------------------------------------------------
       
  4172 //
       
  4173 TMsvId CMmsServerMtm::FindMMSFolderL()
       
  4174     {
       
  4175     // Actually the value in iMmsSettings should be correct
       
  4176     // but we try to really search for the folder in case
       
  4177     // the message store has been moved or something
       
  4178     TMsvId mmsFolderId = iMmsSettings->NotificationFolder();
       
  4179     TInt error;
       
  4180     
       
  4181     // get a new entry, don't mess up with the original entry.
       
  4182     CMsvServerEntry* workingEntry = NULL;
       
  4183     TRAP( error, workingEntry = iServerEntry->NewEntryL( KMsvLocalServiceIndexEntryId ) );
       
  4184     CleanupStack::PushL( workingEntry );
       
  4185     
       
  4186     if ( error == KErrNoMemory )
       
  4187         {
       
  4188         CleanupStack::PopAndDestroy( workingEntry );
       
  4189         User::Leave( error );
       
  4190         }
       
  4191 
       
  4192     if ( error != KErrNone )
       
  4193         {
       
  4194         // no can do
       
  4195         CleanupStack::PopAndDestroy( workingEntry );
       
  4196         return mmsFolderId;
       
  4197         }
       
  4198 
       
  4199     // Get List of services
       
  4200     // show invisible entries
       
  4201     TMsvSelectionOrdering ordering =
       
  4202         TMsvSelectionOrdering( KMsvNoGrouping, EMsvSortByIdReverse, ETrue );
       
  4203     workingEntry->SetSort( ordering );
       
  4204     CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
       
  4205     error = workingEntry->GetChildrenWithType( KUidMsvFolderEntry, *selection );
       
  4206     if ( error != KErrNone )
       
  4207         {
       
  4208         // no can do
       
  4209         delete selection;
       
  4210         if ( error == KErrNoMemory )
       
  4211             {
       
  4212             CleanupStack::PopAndDestroy( workingEntry );
       
  4213             User::Leave( error );
       
  4214             }
       
  4215         else
       
  4216             {
       
  4217             CleanupStack::PopAndDestroy( workingEntry );
       
  4218             return mmsFolderId;
       
  4219             }
       
  4220         }
       
  4221     CleanupStack::PushL( selection );
       
  4222 
       
  4223     // Now we should have a list of all local folders.
       
  4224     // prune away the standard folders.
       
  4225     // They should be at the end of the list
       
  4226 
       
  4227     TInt count = selection->Count();
       
  4228     TInt i;
       
  4229 
       
  4230     for ( i = count - 1; i >= 0; i-- )
       
  4231         {
       
  4232         if ( selection->At( i ) <= KMsvDeletedEntryFolderEntryId )
       
  4233             {
       
  4234             // Anything below this should not be ours
       
  4235             selection->Delete( i );
       
  4236             }
       
  4237         }
       
  4238 
       
  4239     // anything left...
       
  4240     count = selection->Count();
       
  4241 
       
  4242     for ( i = 0; i < count && mmsFolderId == KMsvNullIndexEntryId ; i++ )
       
  4243         {
       
  4244         error = workingEntry->SetEntry( selection->At( i ) );
       
  4245         if ( error == KErrNoMemory )
       
  4246             {
       
  4247             CleanupStack::PopAndDestroy( selection );
       
  4248             CleanupStack::PopAndDestroy( workingEntry );
       
  4249             User::Leave( error );
       
  4250             }
       
  4251         // must be exact match
       
  4252         if ( error == KErrNone &&
       
  4253             workingEntry->Entry().iDetails.Compare( KMMSNotificationFolder ) == 0 )
       
  4254             {
       
  4255             mmsFolderId = selection->At( i );
       
  4256             }
       
  4257         }
       
  4258     CleanupStack::PopAndDestroy( selection );
       
  4259     CleanupStack::PopAndDestroy( workingEntry );
       
  4260 
       
  4261     return mmsFolderId;
       
  4262     }
       
  4263 
       
  4264 // ---------------------------------------------------------
       
  4265 // CMmsServerMtm::DiskSpaceBelowCriticalForScheduling
       
  4266 // 
       
  4267 // ---------------------------------------------------------
       
  4268 //
       
  4269 TBool CMmsServerMtm::DiskSpaceBelowCriticalForSchedulingL( RFs* aFs,
       
  4270             TInt aBytesToWrite, TInt aMessageDrive)
       
  4271     {
       
  4272     TBool belowCritical = EFalse; // optimistic
       
  4273     // The amount of memory needed depends on the number of messages to handle
       
  4274     belowCritical = TMmsGenUtils::DiskSpaceBelowCriticalLevelL(
       
  4275         aFs, KMmsTaskSpace * iMsvSelection->Count(), EDriveC );
       
  4276     if ( !belowCritical )
       
  4277         {
       
  4278         belowCritical = TMmsGenUtils::DiskSpaceBelowCriticalLevelL(
       
  4279             aFs, aBytesToWrite, aMessageDrive );
       
  4280         }
       
  4281     return belowCritical;
       
  4282     }
       
  4283 
       
  4284 // ---------------------------------------------------------
       
  4285 // CMmsServerMtm::ScheduleSelectionL
       
  4286 // 
       
  4287 // ---------------------------------------------------------
       
  4288 //
       
  4289 TInt CMmsServerMtm::ScheduleSelectionL()
       
  4290     {
       
  4291 #ifndef _NO_MMSS_LOGGING_
       
  4292     TMmsLogger::Log( _L("CMmsServerMtm::ScheduleSelectionL") );
       
  4293 #endif
       
  4294     
       
  4295     TInt error = KErrNone;
       
  4296     TInt i;
       
  4297     if ( iMsvSelection->Count() > 0 )
       
  4298         {
       
  4299         TCommandParameters param;
       
  4300         TPckgC<TCommandParameters> paramPack( param );
       
  4301         paramPack.Set( iParameter );
       
  4302 
       
  4303         MakeDatesIdenticalL( *iMsvSelection, paramPack().iInitialDelay, ETrue );
       
  4304         // Query about disk space.
       
  4305         // Subroutine knows how much must be checked for task scheduler
       
  4306         if ( DiskSpaceBelowCriticalForSchedulingL( &iFs, 0, iMessageDrive ) )
       
  4307             {
       
  4308             // we use standard error code here
       
  4309             error = KErrDiskFull;
       
  4310             }
       
  4311         else
       
  4312             {
       
  4313             // We must set the caller's status to KRequest Pending because
       
  4314             // CScheduleBaseServerMtm::ScheduleL does not do it.
       
  4315             *iRequestStatus = KRequestPending;
       
  4316             TRAP( error, ScheduleL( *iMsvSelection, EFalse, iParameter, *iRequestStatus ) );
       
  4317             // ScheduleL would complete our caller, but if it leaves,
       
  4318             // we must complete. We don't want to leave without cleaning up first.
       
  4319     #ifndef _NO_MMSS_LOGGING_
       
  4320             if ( error != KErrNone )
       
  4321                 {
       
  4322                 TMmsLogger::Log( _L("- ScheduleL left with error %d"), error );
       
  4323                 }
       
  4324     #endif
       
  4325             }
       
  4326         if ( error != KErrNone )
       
  4327             {
       
  4328             // Put the entries into failed state because we could not schedule them.
       
  4329             for ( i = 0; i < iMsvSelection->Count(); i++ )
       
  4330                 {
       
  4331                 if ( iServerEntry->SetEntry( iMsvSelection->At( i ) ) == KErrNone )
       
  4332                     {
       
  4333                     TMsvEntry entry = iServerEntry->Entry();
       
  4334                     TMsvId parent = entry.Parent();
       
  4335 
       
  4336                     TMsvId mmboxFolder = iMmsSettings->MMBoxFolder();
       
  4337                     
       
  4338                     if ( entry.iMtm == KUidMsgMMSNotification && 
       
  4339                         ( parent == KMsvGlobalInBoxIndexEntryIdValue ||
       
  4340                         parent == mmboxFolder ) )
       
  4341                         {
       
  4342                         // if the notification is in mmbox folder and duplicate exists, 
       
  4343                         // the duplicate has to be marked too.
       
  4344                         if ( parent == mmboxFolder )
       
  4345                             {
       
  4346     #ifndef _NO_MMSS_LOGGING_
       
  4347                             TMmsLogger::Log( _L("- parent is mmbox folder") );
       
  4348     #endif
       
  4349                             TRAP_IGNORE( CMmsBaseOperation::MarkDuplicateL(
       
  4350                                 CMmsBaseOperation::EMmsNotificationOperationFailed,
       
  4351                                 *iServerEntry ) );
       
  4352                             }
       
  4353 
       
  4354                         // Mark original notification
       
  4355                         entry = iServerEntry->Entry();
       
  4356                         CMmsBaseOperation::MarkNotificationOperationFailed( entry );
       
  4357                         entry.SetSendingState( KMsvSendStateFailed );
       
  4358                         entry.iError = error;
       
  4359                         entry.SetReadOnly( ETrue );
       
  4360     #ifndef _NO_MMSS_LOGGING_
       
  4361                         TMmsLogger::Log( _L("- marked original notification as failed") );
       
  4362     #endif
       
  4363                         }
       
  4364                     iServerEntry->ChangeEntry( entry );
       
  4365                     }
       
  4366                 }
       
  4367             *iRequestStatus = KRequestPending;
       
  4368             User::RequestComplete( iRequestStatus, error );
       
  4369             }
       
  4370         }
       
  4371     return error;
       
  4372     }
       
  4373 
       
  4374 // ---------------------------------------------------------
       
  4375 // CMmsServerMtm::HandleDummyEntryL
       
  4376 // 
       
  4377 // ---------------------------------------------------------
       
  4378 //
       
  4379 void CMmsServerMtm::HandleDummyEntryL()
       
  4380     {
       
  4381     //
       
  4382     // Get access to the streamstore of the entry
       
  4383     //
       
  4384 #ifndef _NO_MMSS_LOGGING_
       
  4385     TMmsLogger::Log( _L("HandleDummyEntryL()") );
       
  4386 #endif
       
  4387     if ( iMsvSelection->Count() == 0 )
       
  4388         {
       
  4389         User::Leave( KErrNotFound );
       
  4390         }
       
  4391         
       
  4392     User::LeaveIfError( iServerEntry->SetEntry( iMsvSelection->At( 0 ) ) );
       
  4393     CMsvStore* store = iServerEntry->ReadStoreL();
       
  4394     CleanupStack::PushL( store ); // ***
       
  4395     RMsvReadStream ins;
       
  4396     ins.OpenLC( *store, KUidBinaryNotificationStream ); // ***
       
  4397 
       
  4398     //
       
  4399     // Read first 32 bits into integer. It will tell the length of the data
       
  4400     //
       
  4401     TInt datalength = ins.ReadUint32L();
       
  4402 #ifndef _NO_MMSS_LOGGING_
       
  4403     TMmsLogger::Log( _L(" - Streamed %d bytes from dummy-entry's store"), datalength );
       
  4404 #endif
       
  4405 
       
  4406     //
       
  4407     // Reserve correct size buffer
       
  4408     //
       
  4409     if ( !iEncodeBuffer )
       
  4410         {
       
  4411         iEncodeBuffer = CBufFlat::NewL( datalength );
       
  4412         iEncodeBuffer->ResizeL( datalength );
       
  4413         }
       
  4414     else
       
  4415         {
       
  4416         // Throw away old stuff and resize
       
  4417         iEncodeBuffer->Reset();
       
  4418         iEncodeBuffer->ResizeL( datalength );
       
  4419         }
       
  4420     TPtr8 pBuf = iEncodeBuffer->Ptr( 0 );
       
  4421 
       
  4422     //
       
  4423     // Read the data into buffer
       
  4424     //
       
  4425     ins.ReadL( pBuf );
       
  4426     CleanupStack::PopAndDestroy( &ins ); // close in
       
  4427     CleanupStack::PopAndDestroy( store );
       
  4428 
       
  4429     //
       
  4430     // Clean up: the dummy entry is deleted
       
  4431     //
       
  4432     if ( iServerEntry->SetEntry( iServerEntry->Entry().Parent() ) == KErrNone )
       
  4433         {
       
  4434         iServerEntry->DeleteEntry( iMsvSelection->At( 0 ) );
       
  4435         }
       
  4436     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  4437     iMsvSelection->Reset();
       
  4438     }
       
  4439 
       
  4440 // ---------------------------------------------------------
       
  4441 // CMmsServerMtm::HandleMMBoxFlagL
       
  4442 // 
       
  4443 // ---------------------------------------------------------
       
  4444 //
       
  4445 void CMmsServerMtm::HandleMMBoxFlagL( TMsvEntry& aEntry )
       
  4446     {
       
  4447 #ifndef _NO_MMSS_LOGGING_
       
  4448     TMmsLogger::Log( _L("HandleMMBoxFlagL()") );
       
  4449 #endif
       
  4450     // Is there an mmbox field in the notification PDU...
       
  4451     if( iMmsHeaders->MMBoxMessageHeadersL().MmsStored() == 0 )
       
  4452         {
       
  4453         TInt value = 0;
       
  4454         TInt error = KErrNone;
       
  4455         CRepository* repository = NULL;
       
  4456         TRAPD( error2,        
       
  4457             // Notification does not contain explicit field, so checking cenrep
       
  4458             repository = CRepository::NewL( KUidMmsServerMtm ) ); // ***
       
  4459         if ( error2 == KErrNone )
       
  4460             {
       
  4461             CleanupStack::PushL( repository );
       
  4462             #ifndef _NO_MMSS_LOGGING_
       
  4463             TMmsLogger::Log( _L("- repository created") );
       
  4464             #endif
       
  4465             error = repository->Get( KMmsEnginePseudoMMBox, value );
       
  4466             if( error == KErrNone && value == 1 )
       
  4467                 {
       
  4468                 // Assuming MMBox storage in this case
       
  4469                 aEntry.iMtmData2 |= KMmsStoredInMMBox;
       
  4470                 #ifndef _NO_MMSS_LOGGING_
       
  4471                 TMmsLogger::Log( _L("- Setting MMBox flag based on cenrep data!") );
       
  4472                 #endif
       
  4473                 }
       
  4474             else
       
  4475                 {
       
  4476                 #ifndef _NO_MMSS_LOGGING_
       
  4477                 TMmsLogger::Log( _L("- Key not found from cenrep data, or value != 1") );
       
  4478                 #endif
       
  4479                 }
       
  4480             CleanupStack::PopAndDestroy( repository );
       
  4481             }
       
  4482         }
       
  4483     else if( iMmsHeaders->MMBoxMessageHeadersL().MmsStored() == KMmsYes )
       
  4484         {
       
  4485         // Notification specifies the flag as 'yes'
       
  4486         #ifndef _NO_MMSS_LOGGING_
       
  4487         TMmsLogger::Log( _L("- Notification contains stored in mmbox flag!") );
       
  4488         #endif
       
  4489         aEntry.iMtmData2 |= KMmsStoredInMMBox;
       
  4490         }
       
  4491     else
       
  4492         {
       
  4493         // Keep LINT happy
       
  4494         }
       
  4495     }
       
  4496 
       
  4497 // ---------------------------------------------------------
       
  4498 // CMmsServerMtm::GcOutBoxMessagesL
       
  4499 // 
       
  4500 // ---------------------------------------------------------
       
  4501 //
       
  4502 void CMmsServerMtm::GcOutBoxMessagesL()
       
  4503     {
       
  4504 #ifndef _NO_MMSS_LOGGING_
       
  4505     TMmsLogger::Log( _L("CMmsServerMtm::GcOutBoxMessagesL") );
       
  4506 #endif
       
  4507     //
       
  4508     // MMS watcher sends us reason codes with garbage collection parameters.
       
  4509     // paramPack().iReasonFlags will contain the reason flags.
       
  4510     // paramPack().iMediaUnavailableTime tells when the memory card was removed
       
  4511     //
       
  4512     TMMSGarbageCollectionParameters param;
       
  4513     TPckgC<TMMSGarbageCollectionParameters> paramPack( param );
       
  4514     paramPack.Set( iParameter );
       
  4515     
       
  4516     TMsvEntry entry;
       
  4517     
       
  4518     iMsvSelection->Reset();
       
  4519     TInt err = iServerEntry->SetEntry( KMsvGlobalOutBoxIndexEntryId );
       
  4520     // Get entries of type MMS Message
       
  4521     if ( err == KErrNone )
       
  4522         {
       
  4523         err = iServerEntry->GetChildrenWithMtm( KUidMsgTypeMultimedia, *iMsvSelection );
       
  4524         }
       
  4525     TInt count = iMsvSelection->Count();
       
  4526 #ifndef _NO_MMSS_LOGGING_
       
  4527     TMmsLogger::Log( _L("- found %d message entries from outbox"), count );
       
  4528 #endif
       
  4529 
       
  4530     if ( err == KErrNone && count > 0 )
       
  4531         {
       
  4532         // iSendOperation should not be around in this context.
       
  4533         // To avoid possible memory leaks, we clean it away anyway
       
  4534         delete iSendOperation; 
       
  4535         iSendOperation = NULL;
       
  4536         iSendOperation = CMmsSendOperation::NewL( iFs, iMmsSettings );
       
  4537                 
       
  4538         iSendOperation->Failed().AppendL( iMsvSelection->Back( 0 ), count );
       
  4539         iSendOperation->Sent().SetReserveL( count );
       
  4540 
       
  4541         CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
       
  4542         CleanupStack::PushL( selection );
       
  4543         while ( count-- )
       
  4544             {
       
  4545             // The detailed handling depends both on the state of the entry
       
  4546             // and the event that triggered the garbage collection.
       
  4547             // Some states are handled differently depending on the event,
       
  4548             // some states are always hanldled the same way.
       
  4549             if ( iServerEntry->SetEntry( iMsvSelection->At( count ) ) == KErrNone )
       
  4550                 {
       
  4551                 entry = iServerEntry->Entry();
       
  4552                 selection->Reset();
       
  4553                 selection->AppendL( iMsvSelection->At( count ) );
       
  4554                 switch ( entry.SendingState() )
       
  4555                     {
       
  4556                     case KMsvSendStateSent:
       
  4557                         {
       
  4558 #ifndef _NO_MMSS_LOGGING_
       
  4559                         TMmsLogger::Log( _L("- already sent"));
       
  4560 #endif
       
  4561                         // Sent entries are always moved to sent folder (or deleted)
       
  4562                         // regardless of trigger event
       
  4563                         // A sent message should not be in outbox. It should have already been
       
  4564                         // moved to sent folder. However, as it is not moved, we must do it.
       
  4565                         if ( iServerEntry->SetEntry( KMsvGlobalOutBoxIndexEntryId ) == KErrNone )
       
  4566                             {
       
  4567                             if ( iMmsSettings->MoveToSent() )
       
  4568                                 {
       
  4569                                 // Move entry from Outbox to Sent Folder
       
  4570                                 // count has originally been set to iMsvSelection->Count().
       
  4571                                 iServerEntry->MoveEntryWithinService(
       
  4572                                     iMsvSelection->At( count ), KMsvSentEntryIdValue );
       
  4573                                 // This will not fail
       
  4574                                 if ( iSendOperation->Failed().Count() > count )
       
  4575                                     {
       
  4576                                     iSendOperation->Sent().AppendL(
       
  4577                                         iSendOperation->Failed().At( count ) );
       
  4578                                     }
       
  4579                                 }
       
  4580                             else    
       
  4581                                 {
       
  4582                                 // Move entry to Message Heaven
       
  4583                                 iServerEntry->DeleteEntry( iMsvSelection->At( count ) );
       
  4584                                 }
       
  4585                             }
       
  4586                         iSendOperation->Failed().Delete( count );
       
  4587                         break;
       
  4588                         }
       
  4589                     case KMsvSendStateWaiting:
       
  4590                     case KMsvSendStateSending:
       
  4591 #ifndef _NO_MMSS_LOGGING_
       
  4592                         if ( entry.SendingState() == KMsvSendStateWaiting )
       
  4593                             {
       
  4594                             TMmsLogger::Log( _L("- waiting"));
       
  4595                             }
       
  4596                         else
       
  4597                             {
       
  4598                             TMmsLogger::Log( _L("- sending"));
       
  4599                             }
       
  4600 #endif
       
  4601                         if ( paramPack().iReasonFlags &
       
  4602                             ( KMmsReasonHotswap | KMmsReasonBackupEnded ) )
       
  4603                             {
       
  4604                             // reschedule if last time accessed earlier that media unavailable time stamp
       
  4605                             if ( iServerEntry->Entry().iDate > paramPack().iMediaUnavailableTime )
       
  4606                                 {
       
  4607                                 // Access time is after media unavailable,
       
  4608                                 // It means that something has been done to this entry already.
       
  4609                                 // Better leave it as is.
       
  4610 #ifndef _NO_MMSS_LOGGING_
       
  4611                                 TMmsLogger::Log( _L(" -- accessed after media unavailable - leave as is"));
       
  4612 #endif
       
  4613                                 iSendOperation->Failed().Delete( count );
       
  4614                                 }
       
  4615                             }
       
  4616                         else
       
  4617                             {
       
  4618                             iSendOperation->Failed().Delete( count );
       
  4619                             }
       
  4620                         break;
       
  4621                     case KMsvSendStateUponRequest:
       
  4622 #ifndef _NO_MMSS_LOGGING_
       
  4623                         TMmsLogger::Log( _L("- upon request"));
       
  4624 #endif
       
  4625                         // Entries in "upon request" state are not rescheduled
       
  4626                         iSendOperation->Failed().Delete( count );
       
  4627                         break;
       
  4628                     case KMsvSendStateSuspended:
       
  4629 #ifndef _NO_MMSS_LOGGING_
       
  4630                         TMmsLogger::Log( _L("- suspended"));
       
  4631 #endif
       
  4632                         // entries in "upon request" or "suspended" state are not rescheduled
       
  4633                         // unless we have switched from offline mode back to online mode
       
  4634                         if ( !( ( paramPack().iReasonFlags & KMmsReasonNetworkAllowed ) &&
       
  4635                             ( entry.SendingState() == KMmsOffLineState ) &&
       
  4636                             ( entry.iError == KMmsErrorOfflineMode ) ) )
       
  4637                             {
       
  4638                             iSendOperation->Failed().Delete( count );
       
  4639                             }
       
  4640                         break;
       
  4641                     case KMsvSendStateScheduled:
       
  4642                     case KMsvSendStateResend:
       
  4643                         {
       
  4644 #ifndef _NO_MMSS_LOGGING_
       
  4645                         TMmsLogger::Log( _L("- already scheduled"));
       
  4646 #endif
       
  4647                         // These are either rescheduled or scheduled for the first time
       
  4648                         // reschedule if the schedule is in the past
       
  4649                         // If the scedule is in the past, CheckSchedule moves it forward.
       
  4650                         // However, if it is too much in the past, it is moved forward by a year.
       
  4651                         // We must do some sanity chaecking about the amount of change
       
  4652                         
       
  4653                         // we set flag to indicate that our shedule had passed
       
  4654                         TInt oldSchedule = EFalse;
       
  4655                         TTime now;
       
  4656                         now.UniversalTime();
       
  4657                         
       
  4658                         if ( iServerEntry->Entry().iDate < now )
       
  4659                             {
       
  4660                             oldSchedule = ETrue;
       
  4661                             }
       
  4662                         
       
  4663                         iScheduleSend->CheckScheduleL( *selection );
       
  4664                         if ( iServerEntry->Entry().Scheduled() )
       
  4665                             {
       
  4666                             // already scheduled - check, if schedule is valid
       
  4667                             TTime scheduleTime = iServerEntry->Entry().iDate;
       
  4668                             now += TTimeIntervalSeconds( 1 );
       
  4669 #ifndef _NO_MMSS_LOGGING_
       
  4670                             TMmsLogger::Log( _L("MMS terminal universal datetime: ") );
       
  4671                             CMmsBaseOperation::LogDateL( now );
       
  4672                             TMmsLogger::Log( _L("Scheduled datetime:") );
       
  4673                             CMmsBaseOperation::LogDateL( scheduleTime );
       
  4674 #endif
       
  4675                             // leave the schedule, if it is in the future - but not too much
       
  4676                             TTimeIntervalMinutes allowance = 
       
  4677                                 TTimeIntervalMinutes( KMmsScheduleAllowance );
       
  4678                             if ( ( ( ( scheduleTime - allowance ) <= now ) && ( scheduleTime > now ) )
       
  4679                                 || !oldSchedule )
       
  4680                                 {
       
  4681                                 // scheduled in the future, we don't touch it
       
  4682                                 // or the schedule has been originally set into the future,
       
  4683                                 // and we don't want to change it
       
  4684                                 iSendOperation->Failed().Delete( count );
       
  4685                                 }
       
  4686 #ifndef _NO_MMSS_LOGGING_
       
  4687                             else
       
  4688                                 {
       
  4689                                 TMmsLogger::Log( _L("- bad schedule"));
       
  4690                                 }
       
  4691 #endif
       
  4692                             }
       
  4693                         break;
       
  4694                         }
       
  4695                     case KMsvSendStateNotApplicable:
       
  4696 #ifndef _NO_MMSS_LOGGING_
       
  4697                         TMmsLogger::Log( _L("- not applicable"));
       
  4698 #endif
       
  4699                         break;
       
  4700                     case KMsvSendStateUnknown:
       
  4701 #ifndef _NO_MMSS_LOGGING_
       
  4702                         TMmsLogger::Log( _L("- unknown"));
       
  4703 #endif
       
  4704                         break;
       
  4705                     case KMsvSendStateFailed:
       
  4706 #ifndef _NO_MMSS_LOGGING_
       
  4707                         TMmsLogger::Log( _L("- failed"));
       
  4708 #endif
       
  4709                         break;
       
  4710                     default:
       
  4711                         // all entries that are left in the array, are rescheduled in the end
       
  4712                         break;
       
  4713                     }
       
  4714                 }
       
  4715             }
       
  4716         CleanupStack::PopAndDestroy( selection );
       
  4717         iCommand = EMmsSend;
       
  4718         // whatever was left gets rescheduled
       
  4719         MakeDatesIdenticalL( iSendOperation->Failed(), KMmsGarbageCollectionDelay );
       
  4720         TRAP( err, UpdateEntriesL() );
       
  4721         }
       
  4722     }
       
  4723 
       
  4724 // ---------------------------------------------------------
       
  4725 // CMmsServerMtm::GcMmsFolderNotificationsL
       
  4726 // 
       
  4727 // ---------------------------------------------------------
       
  4728 //
       
  4729 void CMmsServerMtm::GcMmsFolderNotificationsL()
       
  4730     {
       
  4731 #ifndef _NO_MMSS_LOGGING_
       
  4732     TMmsLogger::Log( _L("CMmsServerMtm::GcMmsFolderNotificationsL") );
       
  4733 #endif
       
  4734     //
       
  4735     // MMS watcher sends us reason codes with garbage collection parameters.
       
  4736     // paramPack().iReasonFlags will contain the reason flags.
       
  4737     // paramPack().iMediaUnavailableTime tells when the memory card was removed
       
  4738     //
       
  4739     TMMSGarbageCollectionParameters param;
       
  4740     TPckgC<TMMSGarbageCollectionParameters> paramPack( param );
       
  4741     paramPack.Set( iParameter );
       
  4742     
       
  4743     TMsvEntry entry;
       
  4744     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  4745     TMsvId parent = FindMMSFolderL();
       
  4746 
       
  4747     TInt err = iServerEntry->SetEntry( parent );
       
  4748     iMsvSelection->Reset(); 
       
  4749     // All entries in MMSFolder have the same Uid as messages
       
  4750     // There may be notifications, delivery reports and read reports.
       
  4751     // If the whole notification folder has disappeared we cannot have messages either...
       
  4752     if ( err == KErrNone && parent != KMsvNullIndexEntryId )
       
  4753         {
       
  4754         err = iServerEntry->GetChildrenWithType( KUidMsvMessageEntry, *iMsvSelection );
       
  4755         }
       
  4756     TInt count = iMsvSelection->Count();
       
  4757 #ifndef _NO_MMSS_LOGGING_
       
  4758     TMmsLogger::Log( _L(" - found %d notification entries"), iMsvSelection->Count() );
       
  4759 #endif
       
  4760 
       
  4761     if ( err == KErrNone && count > 0 )
       
  4762         {
       
  4763         // iReceiveMessage should not be around in this context.
       
  4764         // To avoid possible memory leaks, we clean it away anyway
       
  4765         delete iReceiveMessage; 
       
  4766         iReceiveMessage = NULL;
       
  4767         iReceiveMessage = CMmsReceiveMessage::NewL( iFs, iMmsSettings  );
       
  4768                 
       
  4769         iReceiveMessage->Failed().AppendL( iMsvSelection->Back( 0 ), count );
       
  4770         iReceiveMessage->Received().SetReserveL( count );
       
  4771 
       
  4772         while ( count-- )
       
  4773             {
       
  4774             if ( iServerEntry->SetEntry( iMsvSelection->At( count ) ) == KErrNone )
       
  4775                 {
       
  4776                 entry = iServerEntry->Entry();
       
  4777                 if ( entry.SendingState() == KMsvSendStateSent )
       
  4778                     {
       
  4779                     // successful entry, delete it
       
  4780                     // This will not fail
       
  4781                     // Read reports are never marked as "sent" so they should not
       
  4782                     // disturb the logic here
       
  4783                     if ( iReceiveMessage->Failed().Count() > count )
       
  4784                         {
       
  4785                         iReceiveMessage->Received().AppendL(
       
  4786                             iReceiveMessage->Failed().At( count ) );
       
  4787                         iReceiveMessage->Failed().Delete( count );
       
  4788                         }
       
  4789                     }
       
  4790                 else if ( ( ( entry.SendingState() == KMsvSendStateWaiting ) || 
       
  4791                     ( entry.SendingState() == KMsvSendStateSending ) ) )
       
  4792                     {
       
  4793                     if ( paramPack().iReasonFlags & ( KMmsReasonHotswap | KMmsReasonBackupEnded ) )
       
  4794                         {
       
  4795                         // These will be rescheduled only if they were accessed the last time
       
  4796                         // before the media unavailable event.
       
  4797                         // Otherwise they might be a new operation.
       
  4798 #ifndef _NO_MMSS_LOGGING_
       
  4799                         TMmsLogger::Log( _L("- hotswap or backup trigger"));
       
  4800 #endif
       
  4801                         if ( entry.iDate > paramPack().iMediaUnavailableTime )
       
  4802                             {
       
  4803                             iReceiveMessage->Failed().Delete( count );
       
  4804                             }
       
  4805                         }
       
  4806                     }
       
  4807                 else if ( entry.iError == KErrNone && entry.iMtmData2 & KMmsNotifyResponseSent )
       
  4808                     {
       
  4809                     // If this is legally deferred, it will not be rescheduled
       
  4810                     CMsvStore* store = iServerEntry->ReadStoreL();
       
  4811                     CleanupStack::PushL( store );
       
  4812                     iMmsHeaders->RestoreL( *store );
       
  4813                     CleanupStack::PopAndDestroy( store );
       
  4814                     if ( iMmsHeaders->Status() == KMmsMessageStatusDeferred )
       
  4815                         {
       
  4816                         // this has been deferred legally - do not reschedule
       
  4817                         iReceiveMessage->Failed().Delete( count );
       
  4818                         }
       
  4819                     }
       
  4820                 else
       
  4821                     {
       
  4822                     // Keep LINT happy
       
  4823                     }
       
  4824                 }
       
  4825             // Here could be a branch that prevents automatic sending of
       
  4826             // messages that have been suspended by user. However, user can suspend
       
  4827             // fetching only in manual mode, and then the notifications are in inbox
       
  4828             }
       
  4829         // Check notifications will remove expired notifications
       
  4830         if ( iReceiveMessage->Failed().Count() > 0 )
       
  4831             {
       
  4832             // only check if there was anything left
       
  4833             CheckNotificationsL( iReceiveMessage->Failed() );
       
  4834             }
       
  4835         iCommand = EMmsReceive;
       
  4836         MakeDatesIdenticalL( iReceiveMessage->Failed(), KMmsGarbageCollectionDelay );
       
  4837         TRAP( err, UpdateEntriesL() );
       
  4838         err = KErrNone; // we don't care about the error, we just do our best
       
  4839         }
       
  4840     }
       
  4841     
       
  4842 // ---------------------------------------------------------
       
  4843 // CMmsServerMtm::GcMmsFolderNotificationsL
       
  4844 // 
       
  4845 // ---------------------------------------------------------
       
  4846 //
       
  4847 void CMmsServerMtm::GcInboxNotifications()
       
  4848     {
       
  4849 #ifndef _NO_MMSS_LOGGING_
       
  4850     TMmsLogger::Log( _L("CMmsServerMtm::GcInboxNotifications") );
       
  4851 #endif
       
  4852     //
       
  4853     // MMS watcher sends us reason codes with garbage collection parameters.
       
  4854     // paramPack().iReasonFlags will contain the reason flags.
       
  4855     // paramPack().iMediaUnavailableTime tells when the memory card was removed
       
  4856     //
       
  4857     TMMSGarbageCollectionParameters param;
       
  4858     TPckgC<TMMSGarbageCollectionParameters> paramPack( param );
       
  4859     paramPack.Set( iParameter );
       
  4860     
       
  4861     TMsvEntry entry;
       
  4862     
       
  4863     TInt err = iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryId );
       
  4864     iMsvSelection->Reset(); 
       
  4865     if ( err == KErrNone )
       
  4866         {
       
  4867         err = iServerEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *iMsvSelection );
       
  4868         }
       
  4869     TInt count = iMsvSelection->Count();
       
  4870 #ifndef _NO_MMSS_LOGGING_
       
  4871     TMmsLogger::Log( _L(" - found %d notifications in inbox"), iMsvSelection->Count() );
       
  4872 #endif
       
  4873     TInt i;
       
  4874     if ( err == KErrNone && count > 0 )
       
  4875         {
       
  4876         for ( i = 0; i < count; i++ )
       
  4877             {
       
  4878             if ( iServerEntry->SetEntry( iMsvSelection->At( i ) ) == KErrNone )
       
  4879                 {
       
  4880                 entry = iServerEntry->Entry();
       
  4881                 
       
  4882                 //
       
  4883                 // If booting and notif is not allowed to start a new operation -> something wrong
       
  4884                 //
       
  4885                 if( ( paramPack().iReasonFlags & ( KMmsReasonBoot ) ) &&
       
  4886                     ( entry.iMtmData2 & KMmsNewOperationForbidden ) )
       
  4887                     {
       
  4888                     entry.iError = KMmsGeneralError;
       
  4889                     CMmsBaseOperation::MarkNotificationOperationFailed( entry );
       
  4890                     entry.SetReadOnly( ETrue );
       
  4891                     entry.iMtmData2 &= ~KMmsOperationIdentifier;
       
  4892                     iServerEntry->ChangeEntry( entry );                 
       
  4893                     }
       
  4894                 }
       
  4895                         
       
  4896             }
       
  4897         }
       
  4898     }
       
  4899     
       
  4900 // ---------------------------------------------------------
       
  4901 // CMmsServerMtm::GcOutBoxNotificationsL
       
  4902 // 
       
  4903 // ---------------------------------------------------------
       
  4904 //
       
  4905 void CMmsServerMtm::GcOutBoxNotificationsL()
       
  4906     {
       
  4907 #ifndef _NO_MMSS_LOGGING_
       
  4908     TMmsLogger::Log( _L("CMmsServerMtm::GcOutBoxNotificationsL") );
       
  4909 #endif
       
  4910     //
       
  4911     // MMS watcher sends us reason codes with garbage collection parameters.
       
  4912     // paramPack().iReasonFlags will contain the reason flags.
       
  4913     // paramPack().iMediaUnavailableTime tells when the memory card was removed
       
  4914     //
       
  4915     TMMSGarbageCollectionParameters param;
       
  4916     TPckgC<TMMSGarbageCollectionParameters> paramPack( param );
       
  4917     paramPack.Set( iParameter );
       
  4918 
       
  4919     //
       
  4920     // Get selection of notifications from Outbox
       
  4921     //
       
  4922     TInt err = iServerEntry->SetEntry( KMsvGlobalOutBoxIndexEntryId );
       
  4923     iMsvSelection->Reset();
       
  4924     if ( err == KErrNone )
       
  4925         {
       
  4926         err = iServerEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *iMsvSelection );
       
  4927         }
       
  4928     TInt count = iMsvSelection->Count();
       
  4929 #ifndef _NO_MMSS_LOGGING_
       
  4930     TMmsLogger::Log( _L("- found %d notification entries from Outbox"), count );
       
  4931 #endif
       
  4932     if( err != KErrNone || count <= 0 )
       
  4933         {
       
  4934 #ifndef _NO_MMSS_LOGGING_
       
  4935         TMmsLogger::Log( _L("- no entries to clean up"), count );
       
  4936 #endif
       
  4937         return;
       
  4938         }
       
  4939 
       
  4940     //
       
  4941     // Creating iForwardOperation  that will handle resends
       
  4942     //
       
  4943     delete iForwardOperation;
       
  4944     iForwardOperation = NULL;
       
  4945     iForwardOperation = CMmsForwardOperation::NewL( iFs, iMmsSettings );                
       
  4946     iForwardOperation->Failed().AppendL( iMsvSelection->Back( 0 ), count );
       
  4947 
       
  4948     CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
       
  4949     CleanupStack::PushL( selection );
       
  4950 
       
  4951     //
       
  4952     // Loop through the found notifications (forward entries)
       
  4953     //
       
  4954     while( count-- )
       
  4955         {
       
  4956         //
       
  4957         // The detailed handling depends both on the state of the entry
       
  4958         // and the event that triggered the garbage collection.
       
  4959         //
       
  4960         TMsvEntry tEntry;
       
  4961         err = iServerEntry->SetEntry( iMsvSelection->At( count ) );
       
  4962         if( err != KErrNone )
       
  4963             {
       
  4964             // If entry not accessible, start a new round
       
  4965             continue;
       
  4966             }
       
  4967         tEntry = iServerEntry->Entry();
       
  4968         selection->Reset();
       
  4969         selection->AppendL( iMsvSelection->At( count ) );
       
  4970 
       
  4971         //
       
  4972         // Switch through based on notification entry's state
       
  4973         //
       
  4974         switch ( tEntry.SendingState() )
       
  4975             {
       
  4976             case KMsvSendStateSuspended:
       
  4977 #ifndef _NO_MMSS_LOGGING_
       
  4978                 TMmsLogger::Log( _L("- KMsvSendStateSuspended"));
       
  4979 #endif
       
  4980                 if( tEntry.iError == KMmsErrorOfflineMode )
       
  4981                     {
       
  4982 #ifndef _NO_MMSS_LOGGING_
       
  4983                     TMmsLogger::Log( _L("- entry error == offline"));
       
  4984 #endif
       
  4985                     if( paramPack().iReasonFlags & KMmsReasonNetworkAllowed )
       
  4986                         {
       
  4987 #ifndef _NO_MMSS_LOGGING_
       
  4988                         TMmsLogger::Log( _L("- GCreason == back-from-offline: rescheduling entry"));
       
  4989 #endif
       
  4990                         // Reschedule entry
       
  4991                         // i.e. nothing done here
       
  4992                         }
       
  4993                     else // GC reason is not "back from offline"
       
  4994                         {
       
  4995 #ifndef _NO_MMSS_LOGGING_
       
  4996                         TMmsLogger::Log( _L("- GCreason != back-from-offline: leaving entry suspended"));
       
  4997 #endif
       
  4998                         // Leave entry suspended (applies to both entry types)
       
  4999                         // i.e. take entryId out from to-be-scheduled list
       
  5000                         iForwardOperation->Failed().Delete( count );
       
  5001                         }
       
  5002                     }
       
  5003                 else // entry.iError not equal to KMmsErrorOfflineMode
       
  5004                     {
       
  5005 #ifndef _NO_MMSS_LOGGING_
       
  5006                     TMmsLogger::Log( _L("- entry error != offline, set forward entry as Failed") );
       
  5007 #endif
       
  5008                     // Set forward entry's send-state to failed
       
  5009                     tEntry.SetFailed( ETrue );
       
  5010 
       
  5011                     // Clear related notification from Inbox:
       
  5012                     // Get the related notification id
       
  5013                     CMsvStore* store = NULL;
       
  5014                     store = iServerEntry->EditStoreL();
       
  5015                     CleanupStack::PushL( store ); // ***
       
  5016                     iMmsHeaders->RestoreL( *store );
       
  5017                     CleanupStack::PopAndDestroy( store );
       
  5018                     TMsvId relatedEntryId = iMmsHeaders->RelatedEntry();
       
  5019                     iMmsHeaders->Reset(); // headers not needed any more
       
  5020 
       
  5021                     if( relatedEntryId != KMsvNullIndexEntryId )
       
  5022                         {
       
  5023 #ifndef _NO_MMSS_LOGGING_
       
  5024                         TMmsLogger::Log( _L("- related notification-entry exists, clearing it") );
       
  5025 #endif
       
  5026                         // Set context (iServerEntry and entry) to notification and clear it
       
  5027                         err = iServerEntry->SetEntry( relatedEntryId );
       
  5028 #ifndef _NO_MMSS_LOGGING_
       
  5029                         if( err != KErrNone )
       
  5030                             {
       
  5031                             TMmsLogger::Log( _L("- ERROR: Could not set entry") );
       
  5032                             }
       
  5033 #endif
       
  5034                         if ( err == KErrNone )
       
  5035                             {
       
  5036                             tEntry = iServerEntry->Entry();
       
  5037                             tEntry.iMtmData2 &= ~KMmsNewOperationForbidden; // not forbidden
       
  5038                             tEntry.iMtmData2 &= ~KMmsOperationOngoing;      // not ongoing
       
  5039                             tEntry.iMtmData2 |= KMmsOperationFinished;      // finished
       
  5040                             tEntry.iMtmData2 |= KMmsOperationResult;        // NOK
       
  5041                             tEntry.SetReadOnly( ETrue );
       
  5042                             err = iServerEntry->ChangeEntry( tEntry );
       
  5043                             }
       
  5044 #ifndef _NO_MMSS_LOGGING_
       
  5045                         if( err != KErrNone )
       
  5046                             {
       
  5047                             TMmsLogger::Log( _L("- ERROR: Could not change related entry") );
       
  5048                             }
       
  5049                         TMmsLogger::Log( _L("- Clear the related-entry link itself") );
       
  5050 #endif
       
  5051 
       
  5052                         // Clear related-id link from forward entry
       
  5053                         err = iServerEntry->SetEntry( iMsvSelection->At( count ) );
       
  5054                         if ( err == KErrNone )
       
  5055                             {
       
  5056                             store = iServerEntry->EditStoreL();
       
  5057                             CleanupStack::PushL( store ); // ***
       
  5058                             iMmsHeaders->RestoreL( *store );
       
  5059                             iMmsHeaders->SetRelatedEntry( KMsvNullIndexEntryId );
       
  5060                             iMmsHeaders->StoreL( *store );
       
  5061                             store->CommitL();
       
  5062                             CleanupStack::PopAndDestroy( store );
       
  5063                             }
       
  5064                         iMmsHeaders->Reset(); // headers not needed any more
       
  5065 #ifndef _NO_MMSS_LOGGING_
       
  5066                         TMmsLogger::Log( _L("- Related-entry and the link cleared") );
       
  5067 #endif
       
  5068                         }
       
  5069 
       
  5070                     // Clean up. 
       
  5071                     // iServerEntry will be needed and set next time
       
  5072                     // at the start of this loop.
       
  5073                     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  5074 
       
  5075                     // Leave entry suspended (applies to both entry types)
       
  5076                     // i.e. take entryId out from to-be-scheduled list
       
  5077 #ifndef _NO_MMSS_LOGGING_
       
  5078                     TMmsLogger::Log( _L("- not scheduling entry") );
       
  5079 #endif
       
  5080                     iForwardOperation->Failed().Delete( count );
       
  5081                     }
       
  5082                 break;
       
  5083             default:
       
  5084 #ifndef _NO_MMSS_LOGGING_
       
  5085                 TMmsLogger::Log( _L("- Forward entry's sendState == %d, not scheduling"), tEntry.SendingState() );
       
  5086 #endif
       
  5087                     iForwardOperation->Failed().Delete( count );
       
  5088                 break;
       
  5089             }
       
  5090         } // while loop
       
  5091 
       
  5092     CleanupStack::PopAndDestroy( selection );
       
  5093     iCommand = EMmsForward;
       
  5094     // whatever was left gets rescheduled
       
  5095     MakeDatesIdenticalL( iForwardOperation->Failed(), KMmsGarbageCollectionDelay );
       
  5096     TRAP( err, UpdateEntriesL() );
       
  5097 #ifndef _NO_MMSS_LOGGING_
       
  5098     if( err != KErrNone )
       
  5099         {
       
  5100         TMmsLogger::Log( _L("- UpdateEntriesL failed with code %d"), err );
       
  5101         }
       
  5102 #endif
       
  5103     }
       
  5104 
       
  5105 // ---------------------------------------------------------
       
  5106 // CMmsServerMtm::GcMmboxFolderNotifications
       
  5107 // 
       
  5108 // ---------------------------------------------------------
       
  5109 //
       
  5110 void CMmsServerMtm::GcMmboxFolderNotifications()
       
  5111     {
       
  5112 #ifndef _NO_MMSS_LOGGING_
       
  5113     TMmsLogger::Log( _L("CMmsServerMtm::GcMmboxFolderNotifications") );
       
  5114 #endif
       
  5115 
       
  5116     TMsvId mmboxFolder = iMmsSettings->MMBoxFolder();
       
  5117     // if mmbox folder is not found, no need to check notifications from there. 
       
  5118     if ( mmboxFolder == KMsvNullIndexEntryId )
       
  5119         {
       
  5120         return;
       
  5121         }
       
  5122 
       
  5123     TInt error = iServerEntry->SetEntry( mmboxFolder );
       
  5124     iMsvSelection->Reset(); 
       
  5125     if ( error == KErrNone )
       
  5126         {
       
  5127         error = iServerEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *iMsvSelection );
       
  5128         }
       
  5129     TInt count = iMsvSelection->Count();
       
  5130 #ifndef _NO_MMSS_LOGGING_
       
  5131     TMmsLogger::Log( _L(" - mmbox folder contains %d notifications"), count );
       
  5132 #endif
       
  5133     if ( error == KErrNone && count > 0 )
       
  5134         {
       
  5135 
       
  5136         for ( TInt i=0; i < count; i++ )
       
  5137             {
       
  5138             if ( iServerEntry->SetEntry( iMsvSelection->At( i ) ) == KErrNone )
       
  5139                 {
       
  5140                 TMsvEntry entry = iServerEntry->Entry();
       
  5141 
       
  5142                 // If forbidden flag is on, mark as failed. 
       
  5143                 if( entry.iMtmData2 & KMmsNewOperationForbidden )
       
  5144                     {             
       
  5145                     entry.iError = KMmsGeneralError;
       
  5146                     entry.SetSendingState( KMsvSendStateSuspended );
       
  5147                     CMmsBaseOperation::MarkNotificationOperationFailed( entry );
       
  5148                     entry.SetReadOnly( ETrue );
       
  5149                     entry.iMtmData2 &= ~KMmsOperationIdentifier;
       
  5150                     iServerEntry->ChangeEntry( entry );
       
  5151                     }           
       
  5152                 }
       
  5153             }
       
  5154         }
       
  5155     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  5156     }
       
  5157 
       
  5158 // ---------------------------------------------------------
       
  5159 // CMmsServerMtm::FindDuplicateNotificationL
       
  5160 // 
       
  5161 // ---------------------------------------------------------
       
  5162 //
       
  5163 TInt CMmsServerMtm::FindDuplicateNotificationL(
       
  5164     TMsvId aParent, CMmsHeaders& aHeaders, TMsvId& aDuplicate )
       
  5165     {
       
  5166 #ifndef _NO_MMSS_LOGGING_
       
  5167     TMmsLogger::Log( _L("CMmsServerMtm::FindDuplicateNotificationL") );
       
  5168 #endif
       
  5169     
       
  5170     aDuplicate = KMsvNullIndexEntryId;
       
  5171  
       
  5172     if ( aParent == KMsvNullIndexEntryId )
       
  5173         {
       
  5174         return KErrNotSupported;
       
  5175         }
       
  5176 
       
  5177     TInt error = iServerEntry->SetEntry( aParent );
       
  5178     if ( error != KErrNone )
       
  5179         {
       
  5180         iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  5181         return error;
       
  5182         }
       
  5183 
       
  5184     CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection; 
       
  5185     CleanupStack::PushL( selection );
       
  5186 
       
  5187     error = iServerEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *selection );
       
  5188 
       
  5189     TInt count = selection->Count();
       
  5190     if ( count == 0 )
       
  5191         {
       
  5192         error = KErrNotSupported;
       
  5193         }
       
  5194 
       
  5195     if ( error != KErrNone  )
       
  5196         {
       
  5197         CleanupStack::PopAndDestroy( selection );
       
  5198         iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  5199         return error;
       
  5200         }
       
  5201 
       
  5202     CMmsHeaders* mmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
       
  5203     CleanupStack::PushL( mmsHeaders );
       
  5204      
       
  5205     for ( TInt i = count; i > 0 && ( aDuplicate == KMsvNullIndexEntryId ); i-- )
       
  5206         {
       
  5207         error = iServerEntry->SetEntry( selection->At( i - 1 ) );
       
  5208         if ( error == KErrNone )
       
  5209             {            
       
  5210             CMsvStore* store = iServerEntry->ReadStoreL();
       
  5211             CleanupStack::PushL( store );
       
  5212             mmsHeaders->RestoreL( *store );
       
  5213             CleanupStack::PopAndDestroy( store );
       
  5214 
       
  5215             // content location must match 
       
  5216             if ( mmsHeaders->ContentLocation().Compare( aHeaders.ContentLocation() ) == 0 )
       
  5217                 {
       
  5218                 // Identical. This probably means that we have not sent a response yet,
       
  5219                 // and MMSC has sent us a new notification.
       
  5220 
       
  5221 #ifndef _NO_MMSS_LOGGING_
       
  5222                TMmsLogger::Log( _L("- content locations match") );
       
  5223 #endif
       
  5224                 TMsvEntry entry = iServerEntry->Entry();
       
  5225                 aDuplicate = entry.Id();
       
  5226                 }
       
  5227 
       
  5228             }
       
  5229         
       
  5230         }
       
  5231 
       
  5232     CleanupStack::PopAndDestroy( mmsHeaders );
       
  5233     CleanupStack::PopAndDestroy( selection );
       
  5234     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  5235 
       
  5236     return error;
       
  5237     }    
       
  5238     
       
  5239 // ---------------------------------------------------------
       
  5240 // CMmsServerMtm::SendReadReportL
       
  5241 // 
       
  5242 // ---------------------------------------------------------
       
  5243 //
       
  5244 void CMmsServerMtm::SendReadReportL()
       
  5245     {
       
  5246     if ( iMsvSelection->Count() > 0 )
       
  5247         {
       
  5248         delete iReadReport;
       
  5249         iReadReport = NULL;
       
  5250         iReadReport = CMmsReadReport::NewL( iFs, iMmsSettings );
       
  5251 
       
  5252         iReadReport->StartL( *iMsvSelection, *iServerEntry,
       
  5253             iServiceEntryId, iStatus );
       
  5254         *iRequestStatus = KRequestPending;
       
  5255         SetActive();    
       
  5256         }
       
  5257     else
       
  5258         {
       
  5259         *iRequestStatus = KRequestPending;
       
  5260         User::RequestComplete( iRequestStatus, KErrNotFound );
       
  5261         }
       
  5262     }
       
  5263     
       
  5264 // ---------------------------------------------------------
       
  5265 // 
       
  5266 // ---------------------------------------------------------
       
  5267 //
       
  5268 void CMmsServerMtm::LogCommandCode( TInt aCommand )
       
  5269     {
       
  5270 #ifndef _NO_MMSS_LOGGING_
       
  5271     switch ( aCommand )
       
  5272         {
       
  5273         case EMmsSend:
       
  5274             TMmsLogger::Log( _L(" - Send") );
       
  5275             break;
       
  5276         case EMmsReceive:
       
  5277             TMmsLogger::Log( _L(" - Receive") );
       
  5278             break;
       
  5279         case EMmsScheduledSend:
       
  5280             TMmsLogger::Log( _L(" - Scheduled send") );
       
  5281             break;
       
  5282         case EMmsScheduledReceive:
       
  5283             TMmsLogger::Log( _L(" - Scheduled fetch") );
       
  5284             break;
       
  5285         case EMmsDeleteSchedule:
       
  5286             TMmsLogger::Log( _L(" - Delete schedule") );
       
  5287             break;
       
  5288         case EMmsDecodePushedMessage:
       
  5289             TMmsLogger::Log( _L(" - Decode pushed message") );
       
  5290             break;
       
  5291         case EMmsLogDeliveryReport:
       
  5292             TMmsLogger::Log( _L(" - Log delivery report") );
       
  5293             break;
       
  5294         case EMmsDeleteEntries:
       
  5295             TMmsLogger::Log( _L(" - Delete entries") );
       
  5296             break;
       
  5297         case EMmsReceiveForced:
       
  5298             TMmsLogger::Log( _L(" - Receive forced") );
       
  5299             break;
       
  5300         case EMmsScheduledReceiveForced:
       
  5301             TMmsLogger::Log( _L(" - Scheduled receive forced") );
       
  5302             break;
       
  5303         case EMmsGarbageCollection:
       
  5304             TMmsLogger::Log( _L(" - Garbage collection") );
       
  5305             break;
       
  5306         case EMmsDeleteExpiredNotifications:
       
  5307             TMmsLogger::Log( _L(" - Delete expired notifications") );
       
  5308             break;
       
  5309         case EMmsRetryServiceLoading:
       
  5310             TMmsLogger::Log( _L(" - Retry because service loading failed!") );
       
  5311             break;
       
  5312         case EMmsMessageGeneration:
       
  5313             TMmsLogger::Log( _L(" - Message generation") );
       
  5314             break;
       
  5315         case EMmsForward:
       
  5316             TMmsLogger::Log( _L(" - EMmsForward") );
       
  5317             break;
       
  5318         case EMmsScheduledForward:
       
  5319             TMmsLogger::Log( _L(" - EMmsScheduledForward") );
       
  5320             break;
       
  5321         case EMmsNotificationDelete:
       
  5322             TMmsLogger::Log( _L(" - EMmsNotificationDelete") );
       
  5323             break;
       
  5324         case EMmsScheduledNotificationDelete:
       
  5325             TMmsLogger::Log( _L(" - EMmsScheduledNotificationDelete") );
       
  5326             break;
       
  5327         case EMmsUpdateMmboxList:
       
  5328             TMmsLogger::Log( _L(" - EMmsUpdateMmboxList") );
       
  5329             break;
       
  5330         case EMmsSendReadReport:
       
  5331             TMmsLogger::Log( _L(" - EMmsSendReadReport") );
       
  5332             break;
       
  5333         case EMmsScheduledReadReport:
       
  5334             TMmsLogger::Log( _L(" - EMmsScheduledReadReport") );
       
  5335             break;
       
  5336         default:
       
  5337             TMmsLogger::Log( _L(" - Unknown command") );
       
  5338             break;
       
  5339         }
       
  5340     TMemoryInfoV1Buf memory;
       
  5341     UserHal::MemoryInfo( memory );
       
  5342     TInt available = memory().iFreeRamInBytes;
       
  5343     TMmsLogger::Log(_L("Free memory %d"), available );
       
  5344 #endif // _NO_MMSS_LOGGING_
       
  5345     }
       
  5346     
       
  5347 // ---------------------------------------------------------
       
  5348 // 
       
  5349 // ---------------------------------------------------------
       
  5350 //
       
  5351 void CMmsServerMtm::GetRealServiceId( CMsvEntrySelection& aSelection )
       
  5352     {
       
  5353     TInt error = KErrNone;
       
  5354     TMsvId messageEntryId = KMsvNullIndexEntryId;
       
  5355     // the function cannot be called without a selection so the selection
       
  5356     // array always has at least one item.
       
  5357     if ( aSelection.Count() > 0 && aSelection.At( 0 ) != KMsvLocalServiceIndexEntryId )
       
  5358         {
       
  5359         messageEntryId = aSelection.At( 0 );
       
  5360         }
       
  5361     else if ( aSelection.Count() > 1 )
       
  5362         {
       
  5363         messageEntryId = aSelection.At( 1 );
       
  5364         }
       
  5365     else
       
  5366         {
       
  5367         // We never get here. This is just a safety valve.
       
  5368         error = KErrNotFound;
       
  5369         }
       
  5370 
       
  5371     // if only a service entry in selection list,
       
  5372     // nothing can be done. If we have only service entry,
       
  5373     // and that is not ours, we won't get here anyway.
       
  5374 
       
  5375     if ( messageEntryId != KMsvNullIndexEntryId )
       
  5376         {
       
  5377         error = iServerEntry->SetEntry( messageEntryId );
       
  5378         }
       
  5379     if ( error == KErrNone )
       
  5380         {
       
  5381         if ( iServerEntry->Entry().iServiceId == KMsvLocalServiceIndexEntryId &&
       
  5382             iServerEntry->Entry().iRelatedId != KMsvNullIndexEntryId )
       
  5383             // This is our actual service.
       
  5384             {
       
  5385             iServiceEntryId = iServerEntry->Entry().iRelatedId;
       
  5386             }
       
  5387         }
       
  5388     }
       
  5389     
       
  5390 // ---------------------------------------------------------
       
  5391 // 
       
  5392 // ---------------------------------------------------------
       
  5393 //
       
  5394 void CMmsServerMtm::HandleLoadServiceError( TInt aError )
       
  5395     {
       
  5396     if ( iCommand == EMmsDecodePushedMessage )
       
  5397         {
       
  5398         // We must delete the dummy entry given to us,
       
  5399         // otherwise nobody will delete it.
       
  5400 
       
  5401         if ( iMsvSelection->Count() > 0 && iMsvSelection->At( 0 ) == iServiceEntryId )
       
  5402             {
       
  5403             iMsvSelection->Delete( 0 ); 
       
  5404             }
       
  5405         if ( iMsvSelection->Count() > 0 )
       
  5406             {
       
  5407             if ( iServerEntry->SetEntry( iMsvSelection->At( 0 ) ) == KErrNone )
       
  5408                 {
       
  5409                 if ( iServerEntry->SetEntry( iServerEntry->Entry().Parent() ) == KErrNone )
       
  5410                     {
       
  5411                     iServerEntry->DeleteEntries( *iMsvSelection );
       
  5412                     }
       
  5413                 }
       
  5414             }
       
  5415         iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  5416 
       
  5417         // If we are trying to decode a notification from WAP stack
       
  5418         // return error to caller, not to ourselves
       
  5419         *iRequestStatus = KRequestPending;
       
  5420         User::RequestComplete( iRequestStatus, aError );
       
  5421         return;
       
  5422         }
       
  5423         
       
  5424     if ( aError == KErrNotFound || aError == KErrNoMemory )
       
  5425         {
       
  5426         // This is a hopeless case.
       
  5427         // It could lead to endless loop.
       
  5428         *iRequestStatus = KRequestPending;
       
  5429         User::RequestComplete( iRequestStatus, aError );
       
  5430         return;
       
  5431         }
       
  5432 
       
  5433     // We only have to help client mtm when it is trying to start automatic
       
  5434     // fetch after changing fetch mode from "deferred" to "on"
       
  5435     if ( iCurrentCommand == EMmsScheduledReceive ||
       
  5436         iCurrentCommand == EMmsScheduledReceiveForced )
       
  5437         {
       
  5438         iCurrentCommand = EMmsRetryServiceLoading;
       
  5439         TRequestStatus* status = &iStatus;
       
  5440         // caller should be in pending state, too.
       
  5441         *iRequestStatus = KRequestPending;
       
  5442         iStatus = KRequestPending;
       
  5443         SetActive();
       
  5444         User::RequestComplete( status, aError );
       
  5445         return;
       
  5446         }
       
  5447     else
       
  5448         {
       
  5449         *iRequestStatus = KRequestPending;
       
  5450         User::RequestComplete( iRequestStatus, aError );
       
  5451         return;
       
  5452         }
       
  5453     }
       
  5454     
       
  5455 // ---------------------------------------------------------
       
  5456 // 
       
  5457 // ---------------------------------------------------------
       
  5458 //
       
  5459 void CMmsServerMtm::LogEntryParent()
       
  5460     {
       
  5461 #ifndef _NO_MMSS_LOGGING_
       
  5462     TMsvId msgEntryId = KMsvNullIndexEntryId;
       
  5463     TInt error = KErrNone;
       
  5464     if ( iMsvSelection->Count() > 0 )
       
  5465         {
       
  5466         msgEntryId = iMsvSelection->At( 0 );
       
  5467         error = iServerEntry->SetEntry( msgEntryId );
       
  5468         if ( error == KErrNone )
       
  5469             {
       
  5470             if ( iServerEntry->Entry().Parent() == KMsvGlobalOutBoxIndexEntryId )
       
  5471                 {
       
  5472                 TMmsLogger::Log( _L("- EntryParent: Outbox") );
       
  5473                 }
       
  5474             else
       
  5475                 {
       
  5476                 TMmsLogger::Log( _L("- EntryParent: 0x%08X"), iServerEntry->Entry().Parent() );
       
  5477                 }
       
  5478             }
       
  5479         }
       
  5480     // free whatever entry we are holding
       
  5481     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  5482 #endif
       
  5483     }
       
  5484     
       
  5485 // ---------------------------------------------------------
       
  5486 // 
       
  5487 // ---------------------------------------------------------
       
  5488 //
       
  5489 void CMmsServerMtm::RestoreVisibilityAndService()
       
  5490     {
       
  5491     TInt error = KErrNone;
       
  5492     TInt i = 0;
       
  5493     TMsvEntry entry;
       
  5494 
       
  5495     // Make sure that the entries are visible.
       
  5496     // If they are "in preparation" that's the caller's problem
       
  5497 
       
  5498     for ( i = 0; i < iMsvSelection->Count(); i++ )
       
  5499         {
       
  5500         error = iServerEntry->SetEntry( iMsvSelection->At( 0 ) );
       
  5501         if ( error == KErrNone )
       
  5502             {
       
  5503             entry = iServerEntry->Entry();
       
  5504             if ( entry.Visible() == EFalse && iCurrentCommand != EMmsDeleteSchedule )
       
  5505                 {
       
  5506                 entry.SetVisible( ETrue );
       
  5507                 // if this fails we cannot help...
       
  5508                 iServerEntry->ChangeEntry( entry );
       
  5509                 }
       
  5510             if ( iCurrentCommand == EMmsDeleteSchedule &&
       
  5511                 entry.iServiceId == KMsvLocalServiceIndexEntryId &&
       
  5512                 entry.iRelatedId != KMsvNullIndexEntryId)
       
  5513                 {
       
  5514                 // restore the correct service id
       
  5515                 entry.iServiceId = entry.iRelatedId;
       
  5516                 entry.iRelatedId = KMsvNullIndexEntryId;
       
  5517                 // if this fails we cannot help...
       
  5518                 iServerEntry->ChangeEntry( entry );
       
  5519                 }
       
  5520             }
       
  5521         }
       
  5522 
       
  5523     // free the entry we are holding
       
  5524     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  5525     }
       
  5526           
       
  5527 // ================= OTHER EXPORTED FUNCTIONS ==============
       
  5528 
       
  5529 #ifndef _NO_MMSS_LOGGING_
       
  5530 const TInt KLogBufferLength = 256;
       
  5531 _LIT(KLogDir, "mmss");
       
  5532 _LIT(KLogFile, "mmss.txt");
       
  5533 
       
  5534 void TMmsLogger::Log(TRefByValue<const TDesC> aFmt,...)
       
  5535     {
       
  5536     VA_LIST list;
       
  5537     VA_START(list, aFmt);
       
  5538 
       
  5539     // Print to log file
       
  5540     TBuf<KLogBufferLength> buf;
       
  5541     buf.FormatList(aFmt, list);
       
  5542 
       
  5543     // Write to log file
       
  5544     RFileLogger::Write(KLogDir, KLogFile, EFileLoggingModeAppend, buf);
       
  5545     }
       
  5546 #endif
       
  5547 
       
  5548 //
       
  5549 // ---------------------------------------------------------
       
  5550 // gPanic implements
       
  5551 // panic function, should be used by debug version only
       
  5552 //
       
  5553 GLDEF_C void gPanic(
       
  5554     TMmsPanic aPanic ) // error number enumerations
       
  5555     {
       
  5556     _LIT( KMmsPanic,"MMS" );
       
  5557     User::Panic( KMmsPanic, aPanic );
       
  5558     }
       
  5559 
       
  5560 //  End of File