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