mmsengine/mmsserver/src/mmsbaseoperation.cpp
changeset 31 ebfee66fde93
child 47 5b14749788d7
child 72 6f657153cbc5
equal deleted inserted replaced
30:6a20128ce557 31:ebfee66fde93
       
     1 /*
       
     2 * Copyright (c) 2004-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:   base class for mms operations
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 
       
    21 // INCLUDE FILES
       
    22 #include    <msventry.h>
       
    23 #include    <logcli.h>
       
    24 #include    <logview.h>
       
    25 // socket error when switching to offline mode
       
    26 #include    <es_sock.h>
       
    27 // Internet error when switching to offline mode
       
    28 #include    <inet6err.h>
       
    29 #include    <CoreApplicationUIsSDKCRKeys.h>
       
    30 #include    <e32property.h> // PubSub
       
    31 #include    <connect/sbdefs.h>
       
    32 #include    <apgcli.h>  // RApaLsSession
       
    33 #include    <fileprotectionresolver.h>
       
    34 #include    <mmsvattachmentmanager.h>
       
    35 
       
    36 #include    "mmsbaseoperation.h"
       
    37 #include    "mmsservercommon.h"
       
    38 #include    "mmserrors.h"
       
    39 #include    "mmssettings.h"
       
    40 #include    "mmsserverentry.h"
       
    41 #include    "mmssession.h"
       
    42 #include    "mmsheaders.h"
       
    43 #include    "mmsdecode.h"
       
    44 #include    "mmsencode.h"
       
    45 #include    "mmsscheduledentry.h"
       
    46 #include    "mmslog.h"
       
    47 #include    "mmsconninit.h"
       
    48 #include    "MmsServerDebugLogging.h"
       
    49 #include    "MmsPhoneClient.H"
       
    50 #include    "mmscodecdatasupplier.h"
       
    51 #include    "mmscodecdatasink.h"
       
    52 #include 	"mmsregisteredapplications.h"
       
    53 
       
    54 // EXTERNAL DATA STRUCTURES
       
    55 
       
    56 // EXTERNAL FUNCTION PROTOTYPES  
       
    57 
       
    58 // CONSTANTS
       
    59 const TInt KMmsBackupWait = 300000000; // wait for 5min, no more
       
    60 const TInt KMmsServerReadyWait = 5000000; // wait for 5 sec for server ready after backup end
       
    61 
       
    62 // MACROS
       
    63 
       
    64 // LOCAL CONSTANTS AND MACROS
       
    65 
       
    66 // MODULE DATA STRUCTURES
       
    67 
       
    68 // LOCAL FUNCTION PROTOTYPES
       
    69 
       
    70 // FORWARD DECLARATIONS
       
    71 
       
    72 // ============================= LOCAL FUNCTIONS ===============================
       
    73 
       
    74 
       
    75 // ============================ MEMBER FUNCTIONS ===============================
       
    76 
       
    77 // -----------------------------------------------------------------------------
       
    78 // CMmsBaseOperation::CMmsBaseOperation
       
    79 // C++ default constructor can NOT contain any code, that
       
    80 // might leave.
       
    81 // -----------------------------------------------------------------------------
       
    82 //
       
    83 CMmsBaseOperation::CMmsBaseOperation( RFs& aFs ):CMsgActive( KMmsActiveObjectPriority ),
       
    84 iFs( aFs )
       
    85     {
       
    86     // As this class is derived from CBase, all uninitialized variables are set to 0.
       
    87     }
       
    88 
       
    89 // -----------------------------------------------------------------------------
       
    90 // CMmsBaseOperation::ConstructL
       
    91 // Symbian 2nd phase constructor can leave.
       
    92 // -----------------------------------------------------------------------------
       
    93 //
       
    94 void CMmsBaseOperation::ConstructL( CMmsSettings* aMmsSettings )
       
    95     {
       
    96     // Default critical state
       
    97     // If nothing is stored, operations just fall through, and there is no error
       
    98     iCriticalState = EMmsOperationEncodingPDU;
       
    99     iMmsSettings = aMmsSettings;
       
   100 
       
   101     // connect to socket to keep connection open as long as we need it
       
   102     TInt error = KErrNone;
       
   103     error = iSocketServ.Connect();
       
   104 #ifndef _NO_MMSS_LOGGING_
       
   105     if ( error != KErrNone )
       
   106         {
       
   107         TMmsLogger::Log( _L("BaseOperation: Connect Socket server returned error %d"), error );
       
   108         }
       
   109 #endif
       
   110     User::LeaveIfError( error );
       
   111     error = iConnection.Open( iSocketServ );
       
   112 #ifndef _NO_MMSS_LOGGING_
       
   113     if ( error != KErrNone )
       
   114         {
       
   115         TMmsLogger::Log( _L("BaseOperation: RConnection::Open returned error %d"), error );
       
   116         }
       
   117 #endif
       
   118     User::LeaveIfError( error );
       
   119     iFailed = new( ELeave ) CMsvEntrySelection;
       
   120     iSuccessful = new( ELeave ) CMsvEntrySelection;
       
   121     iResponse = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
       
   122     iEncoder = CMmsEncode::NewL( iFs );
       
   123     iDecoder = CMmsDecode::NewL( iFs );
       
   124     // expand size is arbitrary. It is not used, we
       
   125     // always allocate the amount we need
       
   126     iEncodeBuffer = CBufFlat::NewL( 0x100 );
       
   127     iMmsSession = CMmsSession::NewL( KMmsActiveObjectPriority, iSocketServ, iConnection );
       
   128     iRemoteParties = new ( ELeave )CDesCArrayFlat( KMmsArrayAllocationNumber );
       
   129     // observe backup/restore event ends
       
   130     iBackupStart = EFalse;
       
   131     iBackupEnd = EFalse;
       
   132     }
       
   133 
       
   134 // -----------------------------------------------------------------------------
       
   135 // CMmsBaseOperation::NewL
       
   136 // Two-phased constructor.
       
   137 // -----------------------------------------------------------------------------
       
   138 //
       
   139 CMmsBaseOperation* CMmsBaseOperation::NewL( RFs& aFs, CMmsSettings* aMmsSettings )
       
   140     {
       
   141     CMmsBaseOperation* self = new( ELeave ) CMmsBaseOperation( aFs );
       
   142     
       
   143     CleanupStack::PushL( self );
       
   144     self->ConstructL( aMmsSettings );
       
   145     CleanupStack::Pop( self );
       
   146 
       
   147     return self;
       
   148     }
       
   149 
       
   150     
       
   151 // Destructor
       
   152 CMmsBaseOperation::~CMmsBaseOperation()
       
   153     {
       
   154     // derived class must cancel.
       
   155 	Cancel();		// framework requirement
       
   156     // iSelection, iServerEntry, and iMmsSettings
       
   157     // are not deleted, because they belong to caller
       
   158 
       
   159 // start of ROAMING CHECK handling
       
   160     delete iPhone;
       
   161 // end ROAMING CHECK handling
       
   162     if ( iRemoteParties )
       
   163         {
       
   164         iRemoteParties->Reset();
       
   165         }
       
   166     delete iRemoteParties;
       
   167     delete iEncodeBuffer;
       
   168     delete iFailed;
       
   169     delete iSuccessful;
       
   170     delete iEntryWrapper;
       
   171     delete iUri;
       
   172     delete iResponse;
       
   173     delete iEncoder;
       
   174     delete iDecoder;
       
   175     delete iMmsLog;
       
   176     delete iLogEvent;
       
   177     delete iLogViewEvent;
       
   178     delete iLogClient;
       
   179     delete iMmsSession;
       
   180 
       
   181     // connection initiator should be NULL already...
       
   182     delete iConnectionInitiator;
       
   183     delete iIAPArray;
       
   184     iConnection.Close();
       
   185     iSocketServ.Close();
       
   186 
       
   187     }
       
   188 
       
   189 // ---------------------------------------------------------
       
   190 // CMmsBaseOperation::NetworkOperationsAllowed()
       
   191 //
       
   192 // ---------------------------------------------------------
       
   193 //
       
   194 TBool CMmsBaseOperation::NetworkOperationsAllowed()
       
   195     {
       
   196     TBool networkAllowed = ETrue; // optimist
       
   197     // If there is no such key, we will continue normally.
       
   198     // This means that in a system where online/offline mode switching
       
   199     // is not supported, we behave as we were always online
       
   200     
       
   201     CRepository* repository = NULL;
       
   202     TInt error = KErrNone;
       
   203     TInt value = ECoreAppUIsNetworkConnectionAllowed;
       
   204     TRAP( error, repository = CRepository::NewL( KCRUidCoreApplicationUIs ) );
       
   205     if( error == KErrNone )
       
   206         {
       
   207         repository->Get( KCoreAppUIsNetworkConnectionAllowed, value );
       
   208         delete repository;
       
   209         repository = NULL;
       
   210         if ( value == ECoreAppUIsNetworkConnectionNotAllowed )
       
   211             {
       
   212             networkAllowed = EFalse;
       
   213             }
       
   214         }
       
   215 
       
   216     return networkAllowed;
       
   217     }
       
   218 
       
   219 // ---------------------------------------------------------
       
   220 // CMmsBaseOperation::AllocateTID
       
   221 //
       
   222 // ---------------------------------------------------------
       
   223 //
       
   224 TInt64 CMmsBaseOperation::AllocateTID()
       
   225     {
       
   226     TTime currentTime;
       
   227     currentTime.UniversalTime();
       
   228     return currentTime.Int64();
       
   229     }
       
   230 
       
   231 // ---------------------------------------------------------
       
   232 // CMmsBaseOperation::StartL
       
   233 //
       
   234 // ---------------------------------------------------------
       
   235 //
       
   236 void CMmsBaseOperation::StartL(
       
   237     CMsvEntrySelection& aSelection,
       
   238     CMsvServerEntry& aServerEntry,
       
   239     TMsvId aService,
       
   240     TRequestStatus& aStatus )
       
   241     {
       
   242 
       
   243 #ifndef _NO_MMSS_LOGGING_
       
   244     TMmsLogger::Log( _L("BaseOperation starting"));
       
   245 #endif
       
   246 
       
   247     InitializeL( aSelection, aServerEntry, aService );
       
   248 
       
   249     if ( iCurrentMessageNo < 1 )
       
   250         {
       
   251         // nothing to send. Give up immediately
       
   252         aStatus = KRequestPending;
       
   253         TRequestStatus* status = &aStatus;
       
   254         User::RequestComplete( status, KErrNotFound );
       
   255         return;
       
   256         }
       
   257 
       
   258     // The first thing to do is to encode the first message.
       
   259     // We don't start connecting before we have something to send
       
   260     // We want to minimize the connection time in order to minimize
       
   261     // the probability of the connection being broken.
       
   262 
       
   263     // In the connect routine we must check that the connection
       
   264     // exists, and open it if it doesn't
       
   265 
       
   266     // the last call in derived class StartL before SetActive() must be Queue.
       
   267     // This will store the caller's status and set it to "request pending" state
       
   268     Queue( aStatus );
       
   269     FallThrough();
       
   270     }
       
   271     
       
   272 // ---------------------------------------------------------
       
   273 // CMmsBaseOperation::ContainsClosedContent
       
   274 //
       
   275 // ---------------------------------------------------------
       
   276 //
       
   277 TInt CMmsBaseOperation::CheckClosedContentL( CMsvServerEntry& aServerEntry, RFs& aFs )
       
   278     {
       
   279     RApaLsSession apaLsSession;
       
   280     TInt err = apaLsSession.Connect();
       
   281     
       
   282     if ( err != KErrNone )
       
   283         {
       
   284         return err;
       
   285         }
       
   286     CleanupClosePushL( apaLsSession );
       
   287     
       
   288     CFileProtectionResolver* fileProt = CFileProtectionResolver::NewLC( aFs );
       
   289         
       
   290     TDataRecognitionResult* dataType = new( ELeave )TDataRecognitionResult;
       
   291     CleanupStack::PushL( dataType );
       
   292         
       
   293     CMsvStore* store = aServerEntry.ReadStoreL();
       
   294     CleanupStack::PushL( store );
       
   295         
       
   296     MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
       
   297     
       
   298     TInt attaCount = attachMan.AttachmentCount();
       
   299         
       
   300     TInt i = 0;
       
   301     // we check all attachments, but if we find even one forbidden type, we give up.
       
   302     for ( i = 0; i < attaCount && err == KErrNone; i++ )
       
   303         {
       
   304        	CMsvAttachment* attaInfo =  attachMan.GetAttachmentInfoL( i );
       
   305         RFile file;
       
   306         err = file.Open( aFs, attaInfo->FilePath(), EFileRead|EFileShareReadersOnly );
       
   307         delete attaInfo;
       
   308         attaInfo = NULL;
       
   309         
       
   310         if ( err == KErrNone )
       
   311             {
       
   312             // We continue only if we managed to open the file successfully    
       
   313             CleanupClosePushL( file );
       
   314         
       
   315             err = apaLsSession.RecognizeData( file, *dataType );
       
   316 #ifndef _NO_MMSS_LOGGING_
       
   317             if ( err != KErrNone )
       
   318                 {
       
   319                 TMmsLogger::Log(_L("- Error in recognization of data type"), err );
       
   320                 // We assume that the file cannot be closed content, if its type
       
   321                 // is not recognized
       
   322                 err = KErrNotSupported;
       
   323                 }
       
   324             else
       
   325                 {
       
   326                 HBufC16* buf16 = HBufC16::NewLC( KMaxFileName );
       
   327                 TPtrC dummy;
       
   328                 TPtr ptr = buf16->Des();
       
   329                 file.Name( ptr );
       
   330                 // we cannot log indefinitely long strings.
       
   331                 // We get this long strings only if the message is corrupted.
       
   332                 dummy.Set( ptr.Left( KMmsMaxLogStringLength ) );
       
   333                 TMmsLogger::Log( _L("- filename: %S"), &dummy );
       
   334                 CleanupStack::PopAndDestroy( buf16 );
       
   335 
       
   336                 TBuf<KMaxDataTypeLength> buffer;
       
   337                 buffer.Copy( dataType->iDataType.Des8() );
       
   338                 TMmsLogger::Log(_L("- Data type recognizer result: %S"), &buffer );
       
   339                 if ( dataType->iConfidence == CApaDataRecognizerType::ECertain )
       
   340                     {
       
   341                     TMmsLogger::Log(_L("- Confidence level: Certain"));
       
   342                     }
       
   343                 else if ( dataType->iConfidence == CApaDataRecognizerType::EProbable )
       
   344                     {
       
   345                     TMmsLogger::Log(_L("- Confidence level: Probable"));
       
   346                     }
       
   347                 else if ( dataType->iConfidence == CApaDataRecognizerType::EPossible )
       
   348                     {
       
   349                     TMmsLogger::Log(_L("- Confidence level: Possible"));
       
   350                     }
       
   351                 else if ( dataType->iConfidence == CApaDataRecognizerType::EUnlikely )
       
   352                     {
       
   353                     TMmsLogger::Log(_L("- Confidence level: Unlikely"));
       
   354                     }
       
   355                 else if ( dataType->iConfidence == CApaDataRecognizerType::ENotRecognized )
       
   356                     {
       
   357                     TMmsLogger::Log(_L("- Confidence level: Not recognized"));
       
   358                     }
       
   359                 else
       
   360                     {
       
   361                     TMmsLogger::Log(_L("- Unknown confidence level"));
       
   362                     }
       
   363                 }
       
   364 #endif
       
   365             // We Must set limit to "possible". The recognition is rather uncertain
       
   366             if ( err == KErrNone && dataType->iConfidence >= CApaDataRecognizerType::EPossible )
       
   367                 {
       
   368                 TInt pos = 0;
       
   369                 file.Seek( ESeekStart, pos ); // rewind just in case
       
   370                 TInt prot = fileProt->ProtectionStatusL( file, dataType->iDataType );
       
   371                 if ( ( prot & ( EFileProtForwardLocked | EFileProtClosedContent ) ) &&
       
   372                     !( prot & EFileProtSuperDistributable ) )
       
   373                     {
       
   374                     err = KMmsErrorProtectedContent;
       
   375                     }
       
   376                 }
       
   377             CleanupStack::PopAndDestroy( &file ); //close file    
       
   378             }
       
   379 #ifndef _NO_MMSS_LOGGING_
       
   380         else
       
   381             {
       
   382             TMmsLogger::Log(_L("- Error in opening file for recognization of data type"), err );
       
   383             }
       
   384 #endif
       
   385         }
       
   386 
       
   387     CleanupStack::PopAndDestroy( store );
       
   388     CleanupStack::PopAndDestroy( dataType );
       
   389     CleanupStack::PopAndDestroy( fileProt );
       
   390         
       
   391     CleanupStack::PopAndDestroy( &apaLsSession ); // close apaSession
       
   392     
       
   393     if ( err == KErrNotSupported )
       
   394         {
       
   395         // the content type was not recognized, we must assume it is not closed content
       
   396         err = KErrNone;
       
   397         }
       
   398     
       
   399     return err;
       
   400     }
       
   401 
       
   402 // ---------------------------------------------------------
       
   403 // CMmsBaseOperation::HandleBackupOperationEventL
       
   404 //
       
   405 // ---------------------------------------------------------
       
   406 //
       
   407 void CMmsBaseOperation::HandleBackupOperationEventL(
       
   408     const TBackupOperationAttributes& aBackupOperationAttributes )
       
   409     {
       
   410     switch ( aBackupOperationAttributes.iOperation )
       
   411         {
       
   412         case EStart:
       
   413             iBackupStart = ETrue;
       
   414             iBackupEnd = EFalse;
       
   415 #ifndef _NO_MMSS_LOGGING_
       
   416             TMmsLogger::Log(_L("Backup/Restore Start"));
       
   417 #endif
       
   418             break;
       
   419         case EEnd:
       
   420         case EAbort:
       
   421             iBackupStart = EFalse;
       
   422             if ( iHaveTimer )
       
   423                 {
       
   424                 iTimer.Cancel();
       
   425                 // Set this to true only if we cancel timer because of backup end
       
   426                 iBackupEnd = ETrue;
       
   427                 // do not do it twice
       
   428                 iDoNotWaitForBackupEnd = ETrue;
       
   429                 iMustWait = ETrue;
       
   430                 }
       
   431 #ifndef _NO_MMSS_LOGGING_
       
   432             if ( aBackupOperationAttributes.iOperation == EEnd )
       
   433                 {
       
   434                 TMmsLogger::Log(_L("Backup/Restore End"));
       
   435                 }
       
   436             else // if not end, then it was abort
       
   437                 {
       
   438                 TMmsLogger::Log(_L("Backup/Restore Abort"));
       
   439                 }
       
   440 #endif
       
   441             break;
       
   442         default:
       
   443             break;
       
   444         }
       
   445     }
       
   446 
       
   447 // ---------------------------------------------------------
       
   448 // CMmsBaseOperation::RunL
       
   449 //
       
   450 // ---------------------------------------------------------
       
   451 //
       
   452 void CMmsBaseOperation::RunL()
       
   453     {
       
   454     // DoRunL() takes the AO through the states, queuing another
       
   455     // asynch step as required.
       
   456     // if DoRunL() detects the end of the cycle it returns
       
   457     // without queuing another cycle.
       
   458 
       
   459     // If Run() would exit without queuing another cycle it reports
       
   460     // completion to the client.
       
   461     // In CMsgActive this is true if the asynch step or DoRunL fails,
       
   462     // or the state cycle is complete
       
   463     // However, we must keep our cycle going in spite of error.
       
   464     // If any step reports an error, we must cleanup the current
       
   465     // operation, and continue to the next entry in the selection.
       
   466     // Only if we lose the connection, we complete the whole loop.
       
   467 
       
   468     // If we have completed ourselves, the error is already in iError.
       
   469     // However, if an asynchronous operation completed us, the error
       
   470     // comes back to us in iStatus.
       
   471     // As we always complete ourselves by returning iError as the
       
   472     // status, we get back either our original iError, or a new
       
   473     // error value set by an asynchronous operation.
       
   474 #ifndef _NO_MMSS_LOGGING_
       
   475     TMmsLogger::Log( _L("BaseOperation RunL status %d, error %d"),
       
   476         iStatus.Int(), iError );
       
   477 #endif
       
   478     TInt status=iStatus.Int();
       
   479 
       
   480     if ( iBackupEnd && ( status == KErrCancel || status == KErrTimedOut ) )
       
   481         {
       
   482         // timer cancelled because of backup end - continue as if no error
       
   483         status = KErrNone;
       
   484         }
       
   485 
       
   486     // wait for 5 seconds after backup end
       
   487     if ( iMustWait )
       
   488         {
       
   489         // Timer is never active if iMustWait == ETrue,
       
   490         // Actually it is not possible to check if iTimer is active.
       
   491         // We must rely on iMustWait.
       
   492         // iMustWait is set true only when the timer was just cancelled
       
   493         // because of backup end, and we must wait a few seconds before continuing.
       
   494         iMustWait = EFalse;
       
   495         iTimer.After( iStatus, KMmsServerReadyWait );
       
   496         SetActive();
       
   497         return;
       
   498         }
       
   499 
       
   500     // when we come here after wait, the timer can go.
       
   501     if ( iHaveTimer )
       
   502         {
       
   503         iTimer.Cancel();
       
   504         iTimer.Close();
       
   505         iHaveTimer = EFalse;
       
   506         iDoNotWaitForBackupEnd = ETrue;
       
   507         iBackupEnd = EFalse;
       
   508         }
       
   509 
       
   510     if ( status <= (TInt) KMsvMediaUnavailable &&
       
   511         status >= (TInt) KMsvIndexRestore &&
       
   512         !iDoNotWaitForBackupEnd )
       
   513         {
       
   514 #ifndef _NO_MMSS_LOGGING_
       
   515         TMmsLogger::Log( _L("- must wait for backup end ") );
       
   516 #endif
       
   517         iState = EMmsOperationWaitingForBackupEnd;
       
   518         // This will take us back to RunL
       
   519         WaitForBackupEnd();
       
   520         // iError has been set when the media unavailable error has occurred.
       
   521         if ( iError == status )
       
   522             {
       
   523             iError = KErrNone;
       
   524             }
       
   525         return;
       
   526         }
       
   527         
       
   528     if ( iState == EMmsOperationCheckingRoaming )
       
   529         {
       
   530         // the status is the result of the roaming query
       
   531         iRegistrationStatus = status;
       
   532         delete iPhone;
       
   533         iPhone = NULL;
       
   534         if ( status > 0 )
       
   535             {
       
   536             // If the status is a successful registration state result,
       
   537             // it must not be set into iError
       
   538             // However, if something has gone wrong, the error should
       
   539             // be propagated.
       
   540             status = 0;
       
   541             }
       
   542         }
       
   543 
       
   544     // Don't override old error.
       
   545     // Connection state returns index of successful connection in status,
       
   546     // it must be handled separately.
       
   547     // And if logging fails, the error is not stored.
       
   548     // Logging is done on "best effort" basis
       
   549     if ( iError == KErrNone &&
       
   550         iState != EMmsOperationConnectingToIAP &&
       
   551         iState != EMmsOperationLogging)
       
   552         {
       
   553         iError = status;
       
   554         }
       
   555 
       
   556     // The connection may go wrong, which means there's no use continuing now.
       
   557     // On the other hand, if one operation fails, the next one may be all right.
       
   558     // We don't exit in the middle of the loop without deciding
       
   559     // what cleanup work must be done.
       
   560     // Only cancel can exit.
       
   561     if ( status != KErrCancel )
       
   562         {
       
   563         // iError contains the possible error from previous step.
       
   564         // It may be needed to decide what to do with current message
       
   565         // in next step.
       
   566         TRAPD( error,DoRunL() );    // continue operations, may re-queue
       
   567         // must not requeue in error situations
       
   568         // If we want to continue the loop in spite of error,
       
   569         // we must not leave, but return the error in iError.
       
   570         // Symbian code may leave, so we must trap the leaves here,
       
   571         // as we want to keep the loop going unless something
       
   572         // is really fatally wrong (we are completely out of memory,
       
   573         // or the system has crashed)
       
   574 #ifndef _NO_MMSS_LOGGING_
       
   575         if ( error != KErrNone )
       
   576             {
       
   577             TMmsLogger::Log(_L("BaseOperatin DoRunL left with error %d"),
       
   578                 error );
       
   579             if ( IsActive() )
       
   580                 {
       
   581                 TMmsLogger::Log(_L("- still active!"));
       
   582                 }
       
   583             }
       
   584 #endif
       
   585         __ASSERT_DEBUG( error==KErrNone || !IsActive(), User::Invariant() );
       
   586         if ( IsActive() ) // requeued
       
   587             {
       
   588             return;
       
   589             }
       
   590         status=error;
       
   591         if ( error == KErrNone )
       
   592             {
       
   593             // If DoRunL did not leave, possible error is in iError
       
   594             status = iError;
       
   595             }
       
   596         }
       
   597     
       
   598     Complete( status );
       
   599     }
       
   600 
       
   601 // ---------------------------------------------------------
       
   602 // CMmsBaseOperation::DoRunL
       
   603 //
       
   604 // ---------------------------------------------------------
       
   605 //
       
   606 void CMmsBaseOperation::DoRunL()
       
   607     {
       
   608 
       
   609     // This routine takes the state machine through the states
       
   610     // until an error is encountered or the cycle completes.
       
   611 
       
   612     if ( iState != EMmsOperationFinalizing )
       
   613         {
       
   614         SelectNextState();
       
   615         // If appropriate, ChangeState makes us active again
       
   616         ChangeStateL();
       
   617         }
       
   618     else
       
   619         {
       
   620         iState = EMmsOperationIdle;
       
   621         iStatus = iError;
       
   622         // If we return from DoRunL without becoming active again,
       
   623         // RunL completes.
       
   624         }
       
   625     }
       
   626 
       
   627 // ---------------------------------------------------------
       
   628 // CMmsBaseOperation::DoComplete
       
   629 //
       
   630 // ---------------------------------------------------------
       
   631 //
       
   632 void CMmsBaseOperation::DoComplete( TInt& aError )
       
   633     {
       
   634 
       
   635 #ifndef _NO_MMSS_LOGGING_
       
   636     TMmsLogger::Log( _L("BaseOperation DoComplete"));
       
   637 #endif
       
   638     // We should get here if we are cancelled, or if
       
   639     // the cycle has completed (with or without error)
       
   640 
       
   641     // Only final cleanup can be done here, nothing asychronous is allowed
       
   642 
       
   643     UnSetSendMask( *iFailed, aError );
       
   644 
       
   645     }
       
   646 
       
   647 // ---------------------------------------------------------
       
   648 // CMmsBaseOperation::DoCancel
       
   649 //
       
   650 // ---------------------------------------------------------
       
   651 //
       
   652 void CMmsBaseOperation::DoCancel()
       
   653     {
       
   654 #ifndef _NO_MMSS_LOGGING_
       
   655     TMmsLogger::Log( _L("BaseOperation DoCancel"));
       
   656 #endif
       
   657     // cancel anything that is still active
       
   658 
       
   659     if ( iPhone )
       
   660         {
       
   661         iPhone->Cancel();
       
   662         }
       
   663     if ( iDecoder )
       
   664         {
       
   665         iDecoder->Cancel();
       
   666         }
       
   667     if ( iEncoder )
       
   668         {
       
   669         iEncoder->Cancel();
       
   670         }
       
   671     if ( iConnectionInitiator )
       
   672         {
       
   673         iConnectionInitiator->Cancel();
       
   674         }
       
   675     if ( iMmsSession )
       
   676         {
       
   677         iMmsSession->Cancel();
       
   678         }
       
   679     if ( iHaveTimer )
       
   680         {
       
   681         iTimer.Cancel();
       
   682         iTimer.Close();
       
   683         iHaveTimer = EFalse;
       
   684         }
       
   685 
       
   686     CMsgActive::DoCancel();
       
   687     if ( iError == KErrNone )
       
   688         {
       
   689         iError = KErrCancel;
       
   690         }
       
   691 
       
   692     }
       
   693 
       
   694 // ---------------------------------------------------------
       
   695 // CMmsBaseOperation::SelectNextState
       
   696 //
       
   697 // ---------------------------------------------------------
       
   698 //
       
   699 void CMmsBaseOperation::SelectNextState()
       
   700     {
       
   701 
       
   702     // If appropriate, the functions called within the switch statement
       
   703     // will make us active again. If all is done, the asynchronous request
       
   704     // will complete
       
   705 
       
   706     // iCritical state determines the state where the operation must be
       
   707     // continued if progress is interrupted by an error caused by backup/restore.
       
   708     // The critical state changes when enough information has been saved so
       
   709     // that backtracking is no longer needed. The critical state is always a 
       
   710     // stat where information is read from disk or stored to disk, because
       
   711     // disk operations may fail because of backup/restore.
       
   712     // Continuation is usually possible only after backup, not after restore,
       
   713     // but because available events do not specify which operation is in progress,
       
   714     // every situation must be handled as if it would be possible to continue
       
   715     // as soon as disk files can be accessed again.
       
   716 
       
   717     switch ( iState )
       
   718         {
       
   719         case EMmsOperationIdle:
       
   720             iState = EMmsOperationCheckingRoaming;
       
   721             break;
       
   722         case EMmsOperationCheckingRoaming:
       
   723             // check what we got from the roaming query and adjust any 
       
   724             // roaming state dependent modes needed by the operation
       
   725             GetRoamingState();
       
   726             iState = EMmsOperationEncodingPDU;
       
   727             break;
       
   728         case EMmsOperationEncodingPDU:
       
   729             if ( iConnected )
       
   730                 {
       
   731                 iState = EMmsOperationSubmittingTransaction;
       
   732                 }
       
   733             else
       
   734                 {
       
   735                 iState = EMmsOperationConnectingToIAP;
       
   736                 }
       
   737             iCriticalState = EMmsOperationCreatingEntry;
       
   738             break;
       
   739         case EMmsOperationConnectingToIAP:
       
   740             CheckConnectionState();
       
   741             if ( iConnected )
       
   742                 {
       
   743                 iState = EMmsOperationInitializingSession;
       
   744                 }
       
   745             else
       
   746                 {
       
   747                 // if could not connect, give up
       
   748                 iState = EMmsOperationUpdatingEntryStatus; 
       
   749                 }
       
   750             break;
       
   751         case EMmsOperationInitializingSession:
       
   752             iState = EMmsOperationSubmittingTransaction;
       
   753             break;
       
   754         case EMmsOperationSubmittingTransaction:
       
   755             iState = EMmsOperationCreatingEntry;
       
   756             iCriticalState = EMmsOperationCreatingEntry;
       
   757             break;
       
   758         case EMmsOperationCreatingEntry:
       
   759             iState = EMmsOperationDecodingResponse;
       
   760             break;
       
   761         case EMmsOperationDecodingResponse:
       
   762             iState = EMmsOperationStoringResponseData;
       
   763             iCriticalState = EMmsOperationStoringResponseData;
       
   764             break;
       
   765         case EMmsOperationStoringResponseData:
       
   766             iState = EMmsOperationEncodingAck;
       
   767             iCriticalState = EMmsOperationUpdatingEntryStatus;
       
   768             break;
       
   769         case EMmsOperationEncodingAck:
       
   770             iState = EMmsOperationSendingAck;
       
   771             break;
       
   772         case EMmsOperationSendingAck:
       
   773             iState = EMmsOperationUpdatingEntryStatus;
       
   774             break;
       
   775         case EMmsOperationUpdatingEntryStatus:
       
   776             iState = EMmsOperationLogging;
       
   777             iCriticalState = EMmsOperationMovingEntry;
       
   778             break;
       
   779         case EMmsOperationLogging:
       
   780             iState = EMmsOperationMovingEntry;
       
   781             break;
       
   782         case EMmsOperationMovingEntry:
       
   783             iCurrentMessageNo--;
       
   784             if ( iCurrentMessageNo > 0 )
       
   785                 {
       
   786                 iState = EMmsOperationEncodingPDU;
       
   787                 iCriticalState = EMmsOperationEncodingPDU;
       
   788                 }
       
   789             else
       
   790                 {
       
   791                 iState = EMmsOperationFinalizing;
       
   792                 iCriticalState = EMmsOperationFinalizing;
       
   793                 }
       
   794             break;
       
   795         case EMmsOperationFinalizing:
       
   796             // no more states
       
   797             break;
       
   798         case EMmsOperationWaitingForBackupEnd:
       
   799             // return to failure point
       
   800             iState = iCriticalState;
       
   801             break;
       
   802         default:
       
   803             // If we are in an illegal state, we don't change it.
       
   804             // The only way we can end here is if someone overwrites
       
   805             // our stack, and in that case things are so terribly wrong
       
   806             // that there is nothing to be done
       
   807             // Change state will terminate the loop.
       
   808 #ifndef _NO_MMSS_LOGGING_
       
   809             TMmsLogger::Log( _L("BaseOperation in illegal state %d "), iState );
       
   810 #endif
       
   811             break;
       
   812         }
       
   813     }
       
   814 
       
   815 // ---------------------------------------------------------
       
   816 // CMmsBaseOperation::ChangeStateL
       
   817 //
       
   818 // ---------------------------------------------------------
       
   819 //
       
   820 void CMmsBaseOperation::ChangeStateL()
       
   821     {
       
   822     switch ( iState )
       
   823         {
       
   824         case EMmsOperationCheckingRoaming:
       
   825             RoamingCheck();
       
   826             break;
       
   827         case EMmsOperationEncodingPDU:
       
   828             EncodePDUL();
       
   829             break;
       
   830         case EMmsOperationConnectingToIAP:
       
   831             ConnectToIAPL();
       
   832             break;
       
   833         case EMmsOperationInitializingSession:
       
   834             InitializeSessionL();
       
   835             break;
       
   836         case EMmsOperationSubmittingTransaction:
       
   837             SubmitTransactionL();
       
   838             break;
       
   839         case EMmsOperationCreatingEntry:
       
   840             CreateEntryL();
       
   841             break;
       
   842         case EMmsOperationDecodingResponse:
       
   843             DecodeResponseL();
       
   844             break;
       
   845         case EMmsOperationStoringResponseData:
       
   846             StoreResponseL();
       
   847             break;
       
   848         case EMmsOperationEncodingAck:
       
   849             EncodeAckL();
       
   850             break;
       
   851         case EMmsOperationSendingAck:
       
   852             SendAckL();
       
   853             break;
       
   854         case EMmsOperationUpdatingEntryStatus:
       
   855             UpdateEntryStatusL();
       
   856             break;
       
   857         case EMmsOperationLogging:
       
   858             LogL();
       
   859             break;
       
   860         case EMmsOperationMovingEntry:
       
   861             MoveEntryL();
       
   862             break;
       
   863         case EMmsOperationFinalizing:
       
   864             FinalizeL();
       
   865             break;
       
   866         case EMmsOperationWaitingForBackupEnd:
       
   867             WaitForBackupEnd();
       
   868             break;
       
   869         case EMmsOperationIdle:
       
   870             // We should not become idle again. This is startup state
       
   871             break;
       
   872         default:
       
   873             // Totally messed up. Someone overwrote the stack.
       
   874             // If we return without becoming active again, the 
       
   875             // cycle completes.
       
   876 #ifndef _NO_MMSS_LOGGING_
       
   877             TMmsLogger::Log( _L("BaseOperation in illegal state %d "), iState );
       
   878 #endif
       
   879             iError = KErrUnknown;
       
   880             iStatus = iError;
       
   881             break;
       
   882         }
       
   883     }
       
   884 
       
   885 
       
   886 // ---------------------------------------------------------
       
   887 // CMmsBaseOperation::FallThrough
       
   888 //
       
   889 // ---------------------------------------------------------
       
   890 //
       
   891 void CMmsBaseOperation::FallThrough()
       
   892     {
       
   893     TRequestStatus* status = &iStatus;
       
   894     iStatus = KRequestPending;
       
   895     SetActive();
       
   896     User::RequestComplete( status, iError );
       
   897     }
       
   898 
       
   899 
       
   900 // ---------------------------------------------------------
       
   901 // CMmsBaseOperation::InitializeL
       
   902 //
       
   903 // ---------------------------------------------------------
       
   904 //
       
   905 void CMmsBaseOperation::InitializeL(
       
   906     CMsvEntrySelection& aSelection,
       
   907     CMsvServerEntry& aServerEntry,
       
   908     TMsvId aService )
       
   909     {
       
   910 
       
   911 #ifndef _NO_MMSS_LOGGING_
       
   912     TMmsLogger::Log( _L("BaseOperation Initialize"));
       
   913 #endif
       
   914 
       
   915     iSelection = &aSelection;
       
   916     iServerEntry = &aServerEntry;
       
   917     iService = aService;
       
   918 
       
   919     iDoNotWaitForBackupEnd = EFalse;
       
   920     iCriticalState = EMmsOperationEncodingPDU;
       
   921 
       
   922     delete iEntryWrapper;
       
   923     iEntryWrapper = NULL;
       
   924     iEntryWrapper = CMmsServerEntry::NewL(
       
   925         iFs,
       
   926         aServerEntry,
       
   927         iService );
       
   928 
       
   929     iFailed->Reset();
       
   930     iSuccessful->Reset();
       
   931     iResponse->Reset();
       
   932 
       
   933     iCurrentMessageNo = iSelection->Count();
       
   934     iError = KErrNone;
       
   935 
       
   936     // clean these in case the class is reused
       
   937     delete iUri;
       
   938     iUri = NULL;
       
   939     delete iIAPArray;
       
   940     iIAPArray = NULL;
       
   941     iConnectionIndex = 0;
       
   942     iRegistrationStatus = 0; // hope for the best
       
   943 
       
   944     // Initialize everything into the failed list.
       
   945     // Very pessimistic indeed.
       
   946 
       
   947     if ( iCurrentMessageNo > 0 )
       
   948         {
       
   949         iFailed->AppendL( iSelection->Back( 0 ), iCurrentMessageNo );
       
   950         iSuccessful->SetReserveL( iCurrentMessageNo );
       
   951         }
       
   952 
       
   953     SetSendMask( *iFailed );
       
   954     
       
   955     //
       
   956     // NOTE: receive operation must override this setting to 'iLocalModeIn'
       
   957     //
       
   958     if ( iMmsSettings->LocalMode() )
       
   959         {
       
   960         iFs.SetSessionPath( iMmsSettings->LocalModeOut() );
       
   961         }
       
   962     }
       
   963 
       
   964 // ---------------------------------------------------------
       
   965 // CMmsBaseOperation::EncodePDUL
       
   966 //
       
   967 // ---------------------------------------------------------
       
   968 //
       
   969 void CMmsBaseOperation::EncodePDUL()
       
   970     {
       
   971     // This state is quite variable.
       
   972     // Each operation will need to know what to encode,
       
   973     // no common implementation available.
       
   974 #ifndef _NO_MMSS_LOGGING_
       
   975     TMmsLogger::Log( _L("BaseOperation EncodePDUL - FallThrough"));
       
   976 #endif
       
   977 
       
   978     // this always starts a new round. iError should be cleared.
       
   979     FallThrough();
       
   980 
       
   981     }
       
   982 
       
   983 // ---------------------------------------------------------
       
   984 // CMmsBaseOperation::ConnectToIAPL
       
   985 //
       
   986 // ---------------------------------------------------------
       
   987 //
       
   988 void CMmsBaseOperation::ConnectToIAPL()
       
   989     {
       
   990 
       
   991 #ifndef _NO_MMSS_LOGGING_
       
   992     TMmsLogger::Log( _L("BaseOperation Connect to IAP"));
       
   993 #endif
       
   994 
       
   995     if ( iError != KErrNone )
       
   996         {
       
   997         FallThrough();
       
   998         return;
       
   999         }
       
  1000 
       
  1001     // This operation should be identical for all derived classes.
       
  1002     TRequestStatus* status = &iStatus;
       
  1003 
       
  1004     // clean URI in case the class is used more than once
       
  1005     // Just at the last minute we check if network operations are allowed
       
  1006     if ( !NetworkOperationsAllowed() )
       
  1007         {
       
  1008 #ifdef __WINS__
       
  1009         iStatus = KRequestPending;
       
  1010         SetActive();
       
  1011         User::RequestComplete( status, KMmsErrorOfflineMode );
       
  1012         return;
       
  1013 #else
       
  1014         // if offline is on and global mode is on in HW, normal offline behaviour.
       
  1015         // if offline is on and local mode is on in HW, continue.
       
  1016         // The purpose of this is to allow fetching precreated messages even if
       
  1017         // network operations were not allowed during the first boot.
       
  1018         if ( !iMmsSettings->LocalMode() )
       
  1019             {
       
  1020             iStatus = KRequestPending;
       
  1021             SetActive();
       
  1022             User::RequestComplete( status, KMmsErrorOfflineMode );
       
  1023             return;
       
  1024             }
       
  1025 #endif
       
  1026         }
       
  1027 
       
  1028     // Use WAP AP from Comms database table.
       
  1029     // This contains the home page URI, and is linked to the actual IAP.
       
  1030     TInt count = iMmsSettings->AccessPointCount();
       
  1031     if( !iMmsSettings->LocalMode() )
       
  1032         {
       
  1033         if ( count < 1 )
       
  1034             {
       
  1035             User::Leave( KMmsErrorNoWAPAccessPoint );
       
  1036             }
       
  1037         iIAPArray = new (ELeave) CArrayFixFlat<TUint32>( count );
       
  1038         for( TInt index = 0; index < count; index++ )
       
  1039             {
       
  1040             iIAPArray->AppendL( iMmsSettings->AccessPoint( index ) );
       
  1041             }
       
  1042 
       
  1043         iConnectionInitiator = CMmsConnectionInitiator::NewL();
       
  1044         // CMmsConnInit sets our status to "KRequestPending"
       
  1045         iConnectionInitiator->ConnectL(
       
  1046             iConnection,
       
  1047 			*iIAPArray,	
       
  1048 			iStatus );
       
  1049 
       
  1050         SetActive();
       
  1051         }
       
  1052     else
       
  1053         {
       
  1054         // local mode has no real wap access point
       
  1055         iStatus = KRequestPending;
       
  1056         SetActive();
       
  1057         // we return status 1 (as if we got connection to most
       
  1058         // preferred access point)
       
  1059         User::RequestComplete( status, 1 );
       
  1060         }
       
  1061     }
       
  1062 
       
  1063 // ---------------------------------------------------------
       
  1064 // CMmsBaseOperation::InitializeSessionL
       
  1065 //
       
  1066 // ---------------------------------------------------------
       
  1067 //
       
  1068 void CMmsBaseOperation::InitializeSessionL()
       
  1069     {
       
  1070 
       
  1071 #ifndef _NO_MMSS_LOGGING_
       
  1072     TMmsLogger::Log( _L("BaseOperation InitializeSession"));
       
  1073 #endif
       
  1074 
       
  1075     if ( iError != KErrNone || iMmsSettings->LocalMode() )
       
  1076         {
       
  1077         FallThrough();
       
  1078         return;
       
  1079         }
       
  1080 
       
  1081 // When we are supporting only HTTP, there is no separate session connection stage.
       
  1082 // Session initialization only sets necessary headers. (User agent and UAProf)
       
  1083     delete iUri;
       
  1084     iUri = NULL;
       
  1085     TUint32 iap = 0;
       
  1086     TBool proxyUsed = EFalse;
       
  1087     HBufC8* proxyAddress = NULL;
       
  1088     HBufC* uri = NULL;
       
  1089 
       
  1090     // We are not supposed to be here, if we haven't succeeded
       
  1091     // in making connection to one of specified access points
       
  1092     CMmsConnectionInitiator::GetParametersL( 
       
  1093         iIAPArray->At( iConnectionIndex - 1 ),
       
  1094         iap,
       
  1095         uri, 
       
  1096         proxyUsed,
       
  1097         proxyAddress
       
  1098         );
       
  1099 
       
  1100     // We must remember the uri, it will be used later.
       
  1101     iUri = uri;
       
  1102     uri = NULL;
       
  1103 
       
  1104     CleanupStack::PushL( proxyAddress );
       
  1105     
       
  1106     iMmsSession->OpenL(
       
  1107         ( !proxyAddress )?TPtrC8():proxyAddress->Des(),
       
  1108         proxyUsed,
       
  1109         iMmsSettings->MaximumReceiveSize(),
       
  1110         iMmsSettings->MaximumSendSize(),
       
  1111         iStatus );
       
  1112 
       
  1113     CleanupStack::PopAndDestroy( proxyAddress );
       
  1114     SetActive();
       
  1115 
       
  1116     }
       
  1117 
       
  1118 // ---------------------------------------------------------
       
  1119 // CMmsBaseOperation::SubmitTransactionL
       
  1120 //
       
  1121 // ---------------------------------------------------------
       
  1122 //
       
  1123 void CMmsBaseOperation::SubmitTransactionL()
       
  1124     {
       
  1125     // Standard transaction is sending a PDU to MMSC in global mode
       
  1126     // Local mode will need an override if supported (send and fetch only)
       
  1127     // Fetch will need an override, because it uses HTTP GET
       
  1128     // and not HTTP POST like other operations.
       
  1129 
       
  1130 #ifndef _NO_MMSS_LOGGING_
       
  1131     TMmsLogger::Log( _L("BaseOperation SubmitTransaction"));
       
  1132 #endif
       
  1133 
       
  1134     if ( !iConnected )
       
  1135         {
       
  1136         if ( iError == KErrNone )
       
  1137             {
       
  1138             iError = KErrCouldNotConnect;
       
  1139             }
       
  1140         }
       
  1141         
       
  1142     // This check is needed only when running tests in local mode
       
  1143     // if length of URI is 0, Symbian code will panic    
       
  1144     if ( !iUri )
       
  1145         {
       
  1146         iError = KMmsErrorNoURI1;
       
  1147         }
       
  1148     else if ( iUri->Des().Length() == 0 )
       
  1149         {
       
  1150         iError = KMmsErrorNoURI1;
       
  1151         }
       
  1152     else
       
  1153         {
       
  1154         // keep LINT happy
       
  1155         }
       
  1156 
       
  1157     if ( iError != KErrNone )
       
  1158         {
       
  1159         FallThrough();
       
  1160         return;
       
  1161         }
       
  1162 
       
  1163     // Set entry
       
  1164     TInt error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1165 
       
  1166     //
       
  1167     // Last minute check to make sure entry has not been deleted or suspended 
       
  1168     //
       
  1169     if( error == KErrNone )
       
  1170         {
       
  1171         TMsvEntry entry = iServerEntry->Entry();
       
  1172         if( entry.SendingState() == KMsvSendStateSuspended || entry.Deleted() )
       
  1173             {
       
  1174             // The message has disappeared and we cannot do anything with it.
       
  1175             #ifndef _NO_MMSS_LOGGING_
       
  1176             if ( entry.SendingState() == KMsvSendStateSuspended )
       
  1177                 {
       
  1178                 TMmsLogger::Log( _L("- message in suspended") );
       
  1179                 }
       
  1180             if ( entry.Deleted() )
       
  1181                 {
       
  1182                 TMmsLogger::Log( _L("- message deleted") );
       
  1183                 }
       
  1184             TMmsLogger::Log( _L("-> finished with this entry") );
       
  1185             #endif
       
  1186             // delete entry from the list
       
  1187             iFailed->Delete( iCurrentMessageNo - 1 );
       
  1188 
       
  1189             //
       
  1190             // Set error and fall through
       
  1191             // 
       
  1192             iError = KErrNotFound;
       
  1193             FallThrough();
       
  1194             return;
       
  1195             }
       
  1196         }
       
  1197 
       
  1198     //
       
  1199     // Update the sending state of our trigger
       
  1200     //
       
  1201     if( error == KErrNone )
       
  1202         {
       
  1203         TMsvEntry entry = iServerEntry->Entry();
       
  1204         entry.SetConnected( ETrue );
       
  1205         entry.SetSendingState( KMsvSendStateSending );
       
  1206         // if this fails, our sending state is wrong, but so what...
       
  1207         iServerEntry->ChangeEntry( entry );
       
  1208         }
       
  1209     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  1210 
       
  1211     //
       
  1212     // Send
       
  1213     //
       
  1214     iMmsSession->SendMessageL( iUri->Des(),
       
  1215         *iEncodeBuffer,
       
  1216         *iEncoder,
       
  1217         *iDecoder,
       
  1218         iStatus );
       
  1219     SetActive();
       
  1220     }
       
  1221 
       
  1222 // ---------------------------------------------------------
       
  1223 // CMmsBaseOperation::CreateEntryL
       
  1224 //
       
  1225 // ---------------------------------------------------------
       
  1226 //
       
  1227 void CMmsBaseOperation::CreateEntryL()
       
  1228     {
       
  1229 #ifndef _NO_MMSS_LOGGING_
       
  1230     TMmsLogger::Log( _L("BaseOperation CreateEntry - FallThrough"));
       
  1231 #endif
       
  1232     // When sending messages or command PDUs (forward) there is no entry to create.
       
  1233     // These fall through, only receive message and view MMBox have incoming data.
       
  1234     FallThrough();
       
  1235     }
       
  1236 
       
  1237 // ---------------------------------------------------------
       
  1238 // CMmsBaseOperation::DecodeResponseL
       
  1239 //
       
  1240 // ---------------------------------------------------------
       
  1241 //
       
  1242 void CMmsBaseOperation::DecodeResponseL()
       
  1243     {
       
  1244     // Default action is to decode response into headers.
       
  1245     // The result will be analyzed in StoreResponse function
       
  1246     // There some data may be updated to original entry or just
       
  1247     // error code will be set.
       
  1248 
       
  1249 #ifndef _NO_MMSS_LOGGING_
       
  1250     TMmsLogger::Log( _L("BaseOperation DecodeResponse"));
       
  1251 #endif
       
  1252 
       
  1253     iResponse->Reset();
       
  1254     if ( !( iError != KErrNone || iEncodeBuffer->Size() == 0 ) )
       
  1255         {
       
  1256         // we have got a response - try to decode it
       
  1257         TRAP( iError,
       
  1258             {
       
  1259             // We don't need an actual entry here.
       
  1260             iEntryWrapper->SetCurrentEntry( KMsvNullIndexEntryId );
       
  1261             iDecoder->DecodeHeadersL(
       
  1262                *iEntryWrapper,
       
  1263                *iResponse,
       
  1264                *iEncodeBuffer );
       
  1265             });
       
  1266         // Response status is mandatory in most responses, but not in quite all.
       
  1267         // Some operations may need an override.
       
  1268         if ( iResponse->ResponseStatus() != 0 )
       
  1269             {
       
  1270             MapResponseStatus( *iResponse );
       
  1271             }
       
  1272         }
       
  1273     FallThrough();
       
  1274     }
       
  1275 
       
  1276 // ---------------------------------------------------------
       
  1277 // CMmsBaseOperation::StoreResponseL
       
  1278 //
       
  1279 // ---------------------------------------------------------
       
  1280 //
       
  1281 void CMmsBaseOperation::StoreResponseL()
       
  1282     {
       
  1283 #ifndef _NO_MMSS_LOGGING_
       
  1284     TMmsLogger::Log( _L("BaseOperation StoreResponse - FallThrough"));
       
  1285 #endif
       
  1286     // Here the response from MMSC is stored.
       
  1287     // When receiving message, the results have already been stored while decoding.
       
  1288     // Here the message would become visible.
       
  1289     // However, if there is an error, the error text is saved here for all messages.
       
  1290     // Other information may also be saved to the trigger entry (for example message id).
       
  1291     // When a message is forwarded, the relevant information is stored in the notification.
       
  1292 
       
  1293     FallThrough();
       
  1294     }
       
  1295 
       
  1296 // ---------------------------------------------------------
       
  1297 // CMmsBaseOperation::EncodeAckL
       
  1298 //
       
  1299 // ---------------------------------------------------------
       
  1300 //
       
  1301 void CMmsBaseOperation::EncodeAckL()
       
  1302     {
       
  1303 #ifndef _NO_MMSS_LOGGING_
       
  1304     TMmsLogger::Log( _L("BaseOperation EncodeAck - FallThrough"));
       
  1305 #endif
       
  1306     // Only receive message has ack, others fall through
       
  1307     FallThrough();
       
  1308     }
       
  1309 
       
  1310 // ---------------------------------------------------------
       
  1311 // CMmsBaseOperation::SendAckL
       
  1312 //
       
  1313 // ---------------------------------------------------------
       
  1314 //
       
  1315 void CMmsBaseOperation::SendAckL()
       
  1316     {
       
  1317 #ifndef _NO_MMSS_LOGGING_
       
  1318     TMmsLogger::Log( _L("BaseOperation SendAck - FallThrough"));
       
  1319 #endif
       
  1320     // Only receive message sends ack, others fall through
       
  1321     FallThrough();
       
  1322     }
       
  1323 
       
  1324 // ---------------------------------------------------------
       
  1325 // CMmsBaseOperation::UpdateEntryStatusL
       
  1326 //
       
  1327 // ---------------------------------------------------------
       
  1328 //
       
  1329 void CMmsBaseOperation::UpdateEntryStatusL()
       
  1330     {
       
  1331 #ifndef _NO_MMSS_LOGGING_
       
  1332     TMmsLogger::Log( _L("BaseOperation UpdateEntryStatus - FallThrough"));
       
  1333 #endif
       
  1334     // This will update the status of the trigger as successful
       
  1335     // or unsuccessful
       
  1336     FallThrough();
       
  1337     }
       
  1338 
       
  1339 // ---------------------------------------------------------
       
  1340 // CMmsBaseOperation::MoveEntryL
       
  1341 //
       
  1342 // ---------------------------------------------------------
       
  1343 //
       
  1344 void CMmsBaseOperation::MoveEntryL()
       
  1345     {
       
  1346 #ifndef _NO_MMSS_LOGGING_
       
  1347     TMmsLogger::Log( _L("BaseOperation MoveEntry - FallThrough"));
       
  1348 #endif
       
  1349     // This will need an override
       
  1350     // Send message moves entry to sent folder
       
  1351     // Receive message checks the fate of a notification.
       
  1352     FallThrough();
       
  1353     }
       
  1354 
       
  1355 // ---------------------------------------------------------
       
  1356 // CMmsBaseOperation::LogL
       
  1357 //
       
  1358 // ---------------------------------------------------------
       
  1359 //
       
  1360 void CMmsBaseOperation::LogL()
       
  1361     {
       
  1362 #ifndef _NO_MMSS_LOGGING_
       
  1363     TMmsLogger::Log( _L("BaseOperation Log - FallThrough"));
       
  1364 #endif
       
  1365     // This will need an override - all operations do not log
       
  1366     FallThrough();
       
  1367     }
       
  1368 
       
  1369 // ---------------------------------------------------------
       
  1370 // CMmsBaseOperation::FinalizeL
       
  1371 //
       
  1372 // ---------------------------------------------------------
       
  1373 //
       
  1374 void CMmsBaseOperation::FinalizeL()
       
  1375     {
       
  1376 #ifndef _NO_MMSS_LOGGING_
       
  1377     TMmsLogger::Log( _L("BaseOperation Finalize"));
       
  1378 #endif
       
  1379     FallThrough();
       
  1380     }
       
  1381 
       
  1382 // ---------------------------------------------------------
       
  1383 // CMmsBaseOperation::WaitForBackupEnd
       
  1384 //
       
  1385 // ---------------------------------------------------------
       
  1386 //
       
  1387 void CMmsBaseOperation::WaitForBackupEnd()
       
  1388     {
       
  1389     LOG( _L("BaseOperation WaitForBackupEnd"));
       
  1390     TInt error = KErrNone;
       
  1391     TInt value = 0;
       
  1392     error = RProperty::Get( KUidSystemCategory, conn::KUidBackupRestoreKey, value );
       
  1393 
       
  1394     if( value != conn::ENoBackup && error == KErrNone )
       
  1395         {
       
  1396         // We are not going to wait forever: using a timer
       
  1397         LOG( _L(" - backup running ") );
       
  1398         error = iTimer.CreateLocal();
       
  1399         if( error == KErrNone )
       
  1400             {
       
  1401             iHaveTimer = ETrue;
       
  1402             // The timer cannot be active as it was just created.
       
  1403             // It makes no sense to check.
       
  1404             // And besides it is impossible to check if RTimer is active.
       
  1405             iTimer.After( iStatus, KMmsBackupWait );
       
  1406             SetActive();
       
  1407             return;
       
  1408             }
       
  1409         }
       
  1410 #ifndef _NO_MMSS_LOGGING_
       
  1411     else
       
  1412         {
       
  1413         LOG( _L(" - backup not running ") );
       
  1414         }
       
  1415 #endif
       
  1416 
       
  1417     // No backup - media gone for other reason
       
  1418     iDoNotWaitForBackupEnd = ETrue;
       
  1419     FallThrough();
       
  1420     }
       
  1421 
       
  1422 // ---------------------------------------------------------
       
  1423 // CMmsBaseOperation::SetSendMask
       
  1424 //
       
  1425 // ---------------------------------------------------------
       
  1426 //
       
  1427 void CMmsBaseOperation::SetSendMask( const CMsvEntrySelection& aSelection )
       
  1428     {
       
  1429     TInt index = aSelection.Count();
       
  1430     TInt error = KErrNone;
       
  1431     while ( index-- )
       
  1432         {
       
  1433         error = ( iServerEntry->SetEntry( aSelection[index] ) );
       
  1434         if ( error == KErrNone )
       
  1435             {
       
  1436             TMsvEntry tEntry = iServerEntry->Entry();
       
  1437             // State is set to "sending" as late as possible to allow cancelling
       
  1438             // until the last possible moment
       
  1439             // Error in an entry is set to KErrNone to allow the error
       
  1440             // to be updated in case we fail halfway through a selection, and want to
       
  1441             // set error to unhandled entries.
       
  1442             tEntry.iError = KErrNone;
       
  1443             iServerEntry->ChangeEntry( tEntry );
       
  1444             }
       
  1445         }
       
  1446     // Release the entry
       
  1447     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  1448 
       
  1449     }
       
  1450 
       
  1451 // ---------------------------------------------------------
       
  1452 // CMmsBaseOperation::UnSetSendMask
       
  1453 //
       
  1454 // ---------------------------------------------------------
       
  1455 //
       
  1456 void CMmsBaseOperation::UnSetSendMask( CMsvEntrySelection& aSelection, TInt aError )
       
  1457     {
       
  1458     TInt index = aSelection.Count();
       
  1459 
       
  1460     // If we have a connection error because switching to offline mode
       
  1461     // has interrupted our sending operation, we suspend our failed messges
       
  1462     if ( !NetworkOperationsAllowed() )
       
  1463         {
       
  1464         aError = KMmsErrorOfflineMode;
       
  1465         }
       
  1466 
       
  1467     while ( index-- )
       
  1468         {
       
  1469         UnSetSendMask( aSelection[index], aError );
       
  1470         // When the entry is in no list, it will not be touched by UpDateEntriesL
       
  1471         // function in CMmsServerMtm.
       
  1472         // When we switch back to "online" mode, these enries will automatically
       
  1473         // be rescheluded.
       
  1474         if ( aError == KMmsErrorOfflineMode )
       
  1475             {
       
  1476             aSelection.Delete( index );
       
  1477             }
       
  1478         }
       
  1479     // Release the entry
       
  1480     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  1481     }
       
  1482 
       
  1483 // ---------------------------------------------------------
       
  1484 // CMmsBaseOperation::UnSetSendMask
       
  1485 //
       
  1486 // ---------------------------------------------------------
       
  1487 //
       
  1488 void CMmsBaseOperation::UnSetSendMask( const TMsvId aId, TInt aError )
       
  1489     {
       
  1490     if ( ( iServerEntry->SetEntry( aId ) ) != KErrNone )
       
  1491         {
       
  1492         return; // no can do
       
  1493         }
       
  1494     TInt error = KErrNone;    
       
  1495 
       
  1496     TMsvEntry tEntry = iServerEntry->Entry();
       
  1497     tEntry.SetConnected( EFalse );
       
  1498     tEntry.SetFailed( EFalse ); // optimistic
       
  1499     if ( tEntry.iError == KErrNone )
       
  1500         {
       
  1501         tEntry.iError = aError;
       
  1502         }
       
  1503 
       
  1504     if ( aError == KMmsErrorOfflineMode )
       
  1505         {
       
  1506         // special case: we did not necessarily fail, but we are not allowed to send now
       
  1507         // Set entry to "suspended" state, but do not update recipient so that this does
       
  1508         // not count as a send or receive attempt
       
  1509         tEntry.iError = aError;
       
  1510         // value for KMmsOffLineStae defined in mmsservercommon.h
       
  1511         tEntry.SetSendingState( KMmsOffLineState );
       
  1512         
       
  1513         // if the notification is in inbox or in mmbox folder, its operation flags have to be marked
       
  1514         // that the operation has finished due to offline mode. 
       
  1515         // In addition if notification in mmbox folder has a duplicate, 
       
  1516         // the duplicate has to be marked as well.
       
  1517         TMsvId mmboxFolder = iMmsSettings->MMBoxFolder();
       
  1518         if ( tEntry.Parent() == mmboxFolder )
       
  1519             {
       
  1520 #ifndef _NO_MMSS_LOGGING_
       
  1521             TMmsLogger::Log( _L(" - CMmsBaseOperation:: duplicates has to be searched") );
       
  1522 #endif
       
  1523             TInt err = KErrNone;
       
  1524             TRAP ( err, MarkDuplicateL( EMmsNotificationOperationFailed, *iServerEntry ) );
       
  1525 #ifndef _NO_MMSS_LOGGING_
       
  1526             TMmsLogger::Log( _L("Trap failed: error %d "), err );
       
  1527 #endif
       
  1528             }
       
  1529         // Mark original notification
       
  1530         if ( tEntry.Parent() == mmboxFolder ||
       
  1531             tEntry.Parent() == KMsvGlobalInBoxIndexEntryIdValue )
       
  1532             {
       
  1533             MarkNotificationOperationFailed( tEntry );                   
       
  1534             tEntry.SetReadOnly( ETrue );
       
  1535             }
       
  1536         }
       
  1537     else
       
  1538         {
       
  1539         // we must also update the recipient information
       
  1540         // in case it was not set already.
       
  1541 
       
  1542         // We trap all leaves.
       
  1543         // If we cannot update recipient because we are in very low memory situation,
       
  1544         // that cannot be helped.
       
  1545         // DoCancel and DoComplete cannot leave.
       
  1546 
       
  1547         CMmsScheduledEntry* mmsScheduledEntry = NULL;
       
  1548         TRAP( error, 
       
  1549             {
       
  1550             mmsScheduledEntry = CMmsScheduledEntry::NewL( tEntry );
       
  1551             CleanupStack::PushL( mmsScheduledEntry );
       
  1552             CMsvStore * store = NULL;
       
  1553             store = iServerEntry->EditStoreL();
       
  1554             CleanupStack::PushL( store );
       
  1555             mmsScheduledEntry->RestoreL( *store );
       
  1556             // if status is still NotYetSent, recipient has not been updated yet
       
  1557             if ( mmsScheduledEntry->MmsRecipient().Status() == CMsvRecipient::ENotYetSent )
       
  1558                 {
       
  1559                 UpdateRecipient( tEntry.iError, *mmsScheduledEntry );
       
  1560                 }
       
  1561             mmsScheduledEntry->StoreL( *store );
       
  1562             store->CommitL();
       
  1563             CleanupStack::PopAndDestroy( store );
       
  1564             CleanupStack::PopAndDestroy( mmsScheduledEntry );
       
  1565             };)
       
  1566         mmsScheduledEntry = NULL;
       
  1567 
       
  1568         // Don't override previous error
       
  1569         // We may have entries that have failed for different reasons
       
  1570         if ( tEntry.iError != KErrNone )
       
  1571             {
       
  1572             tEntry.SetFailed( ETrue );
       
  1573             }
       
  1574         }
       
  1575     error = iServerEntry->ChangeEntry( tEntry );
       
  1576     }
       
  1577 
       
  1578 // ---------------------------------------------------------
       
  1579 // CMmsBaseOperation::UpdateRecipient
       
  1580 //
       
  1581 // ---------------------------------------------------------
       
  1582 //
       
  1583 void CMmsBaseOperation::UpdateRecipient( TInt aError, CMmsScheduledEntry& aMmsScheduledEntry )
       
  1584     {
       
  1585     aMmsScheduledEntry.MmsRecipient().Time().UniversalTime();
       
  1586     aMmsScheduledEntry.MmsRecipient().SetError( aError );
       
  1587     if ( aError == KErrNone )
       
  1588         {
       
  1589         aMmsScheduledEntry.MmsRecipient().SetStatus( CMsvRecipient::ESentSuccessfully );
       
  1590         }
       
  1591     else
       
  1592         {
       
  1593         aMmsScheduledEntry.MmsRecipient().SetStatus( CMsvRecipient::EFailedToSend );
       
  1594         }
       
  1595     }
       
  1596 
       
  1597 // ---------------------------------------------------------
       
  1598 // CMmsBaseOperation::MapResponseStatus
       
  1599 //
       
  1600 // ---------------------------------------------------------
       
  1601 //
       
  1602 void CMmsBaseOperation::MapResponseStatus( CMmsHeaders& aResponse )
       
  1603     {
       
  1604 #ifndef _NO_MMSS_LOGGING_
       
  1605     TMmsLogger::Log( _L("BaseOperation MapResponseStatus"));
       
  1606 #endif
       
  1607     // response status was initialize to 0
       
  1608     // KMmsStatusOk = 128
       
  1609 
       
  1610     // This is common respose status mapping. Retrieve status is different,
       
  1611     // MMBox view confirmation uses this mapping.
       
  1612 
       
  1613     switch ( aResponse.ResponseStatus() )
       
  1614         {
       
  1615         case KMmsStatusOk:
       
  1616             // No error, don't change iError
       
  1617             break;
       
  1618         case KMmsErrorPermanentSendingAddressUnresolved:
       
  1619         case KMmsErrorSendingAddressUnresolved:
       
  1620             iError = KMmsErrorStatusMessageAddressUnresolved;
       
  1621             break;
       
  1622         case KMmsErrorTransientSendingAddressUnresolved:
       
  1623             iError = KMmsErrorStatusTransientAddressUnresolved;
       
  1624             break;
       
  1625         case KMmsErrorPermanentMessageNotFound:
       
  1626         case KMmsErrorMessageNotFound:
       
  1627             iError = KMmsErrorStatusMessageNotFound;
       
  1628             break;
       
  1629         case KMmsErrorTransientMessageNotFound:
       
  1630             iError = KMmsErrorStatusTransientMessageNotFound;
       
  1631             break;
       
  1632         case KMmsErrorTransientNetworkProblem:
       
  1633         case KMmsErrorNetworkProblem:
       
  1634             iError = KMmsErrorStatusNetworkProblem;
       
  1635             break;
       
  1636         case KMmsErrorPermanentServiceDenied:
       
  1637         case KMmsErrorServiceDenied:
       
  1638             iError = KMmsErrorStatusServiceDenied;
       
  1639             break;
       
  1640         case KMmsErrorPermanentMessageFormatCorrupt:
       
  1641         case KMmsErrorMessageFormatCorrupt:
       
  1642             iError = KMmsErrorStatusMessageFormatCorrupt;
       
  1643             break;
       
  1644         case KMmsErrorPermanentContentNotAccepted:
       
  1645         case KMmsErrorNoContentAccepted:
       
  1646             iError = KMmsErrorStatusContentNotAccepted;
       
  1647             break;
       
  1648         case KMmsErrorPermanentReplyChargingLimitationsNotMet:
       
  1649             iError = KMmsErrorStatusReplyChargingLimitationsNotMet;
       
  1650             break;
       
  1651         case KMmsErrorPermanentReplyChargingRequestNotAccepted:
       
  1652             iError = KMmsErrorStatusReplyChargingRequestNotAccepted;
       
  1653             break;
       
  1654         case KMmsErrorPermanentReplyChargingForwardingDenied:
       
  1655             iError = KMmsErrorStatusReplyChargingForwardingDenied;
       
  1656             break;
       
  1657         case KMmsErrorPermanentReplyChargingNotSupported:
       
  1658             iError = KMmsErrorStatusReplyChargingNotSupported;
       
  1659             break;
       
  1660         case KMmsErrorTransientFailure:
       
  1661             iError = KMmsErrorStatusTransientFailure;
       
  1662             break;
       
  1663         case KMmsErrorUnspecified:
       
  1664             iError = KMmsErrorStatusUnspecified;
       
  1665             break;
       
  1666         case KMmsErrorPermanentFailure:
       
  1667             iError = KMmsErrorStatusPermanentFailure;
       
  1668             break;
       
  1669         case KMmsErrorUnsupportedMessage:
       
  1670             iError = KMmsErrorStatusUnsupportedMessage;
       
  1671             break;
       
  1672         default:
       
  1673             // No known status, but did not leave either
       
  1674             if ( iError == KErrNone )
       
  1675                 {
       
  1676                 if ( ( iResponse->ResponseStatus() & KMmsErrorRangeMask ) == KMmsErrorTransient )
       
  1677                     {
       
  1678                     iError = KMmsErrorStatusTransientFailure;
       
  1679                     }
       
  1680                 else
       
  1681                     {
       
  1682                     iError = KMmsErrorStatusPermanentFailure;
       
  1683                     }
       
  1684                 }
       
  1685             break;
       
  1686         }
       
  1687     }
       
  1688 
       
  1689 // ---------------------------------------------------------
       
  1690 // CMmsBaseOperation::InitializeLoggingL
       
  1691 //
       
  1692 // ---------------------------------------------------------
       
  1693 //
       
  1694 void CMmsBaseOperation::InitializeLoggingL()
       
  1695     {
       
  1696 #ifndef _NO_MMSS_LOGGING_
       
  1697     TMmsLogger::Log( _L("BaseOperation InitializeLogging"));
       
  1698 #endif
       
  1699     if ( !iLogClient )
       
  1700         {
       
  1701         iLogClient = CLogClient::NewL( iFs );
       
  1702         }
       
  1703     if ( !iLogViewEvent )
       
  1704         {
       
  1705         iLogViewEvent = CLogViewEvent::NewL( *iLogClient );
       
  1706         }
       
  1707     if ( !iMmsLog )
       
  1708         {
       
  1709         iMmsLog = CMmsLog::NewL( *iLogClient, *iLogViewEvent, iFs );
       
  1710         }
       
  1711     if ( !iLogEvent )
       
  1712         {
       
  1713         iLogEvent = CLogEvent::NewL();
       
  1714         }
       
  1715     }
       
  1716 
       
  1717 
       
  1718 // ---------------------------------------------------------
       
  1719 // CMmsBaseOperation::CheckConnectionState
       
  1720 //
       
  1721 // ---------------------------------------------------------
       
  1722 //
       
  1723 void CMmsBaseOperation::CheckConnectionState()
       
  1724     {
       
  1725     TInt status=iStatus.Int();
       
  1726     // these can go now.
       
  1727     delete iConnectionInitiator;
       
  1728     iConnectionInitiator = NULL;
       
  1729     if ( status > 0 )
       
  1730         {
       
  1731         iConnectionIndex = status;
       
  1732         // We say we are connected when we have the connection to IAP.
       
  1733         // When protocol is HTTP there is no separate session opening step.
       
  1734         iConnected = ETrue;
       
  1735         }
       
  1736     else
       
  1737         {
       
  1738         iError = status;
       
  1739         if ( status == KErrGeneral )
       
  1740             {
       
  1741             iError = KErrCouldNotConnect;
       
  1742             }
       
  1743         }
       
  1744     }
       
  1745 // ---------------------------------------------------------
       
  1746 // CMmsBaseOperation::FindDuplicateNotificationL
       
  1747 // 
       
  1748 // ---------------------------------------------------------
       
  1749 //
       
  1750 TInt CMmsBaseOperation::FindDuplicateNotificationL(
       
  1751     TMsvId aParent, CMmsHeaders& aHeaders, TMsvId& aDuplicate )
       
  1752     {
       
  1753 #ifndef _NO_MMSS_LOGGING_
       
  1754     TMmsLogger::Log( _L(" CMmsBaseOperation::FindDuplicateNotificationL") );
       
  1755 #endif
       
  1756 
       
  1757     TInt error = KErrNone;    
       
  1758     aDuplicate = KMsvNullIndexEntryId;
       
  1759     if ( aParent == KMsvNullIndexEntryId )
       
  1760         {
       
  1761         return KErrNotSupported;
       
  1762         }
       
  1763 
       
  1764     CMsvServerEntry* workingEntry = NULL;
       
  1765     TRAP( error, workingEntry = iServerEntry->NewEntryL( aParent ) );
       
  1766     CleanupStack::PushL( workingEntry );
       
  1767     
       
  1768     if ( error != KErrNone )
       
  1769         {
       
  1770         CleanupStack::PopAndDestroy( workingEntry ); // workingEntry
       
  1771         return error;
       
  1772         }
       
  1773 
       
  1774     CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection; 
       
  1775     CleanupStack::PushL( selection );
       
  1776 
       
  1777     error = workingEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *selection );
       
  1778 
       
  1779     TInt count = selection->Count();
       
  1780     if ( count == 0 )
       
  1781         {
       
  1782         error = KErrNotSupported;
       
  1783         }
       
  1784 
       
  1785     if ( error != KErrNone  )
       
  1786         {
       
  1787         CleanupStack::PopAndDestroy( selection );
       
  1788         CleanupStack::PopAndDestroy( workingEntry );
       
  1789         return error;
       
  1790         }
       
  1791 
       
  1792     CMmsHeaders* mmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
       
  1793     CleanupStack::PushL( mmsHeaders );
       
  1794      
       
  1795     for ( TInt i = count; i > 0 && ( aDuplicate == KMsvNullIndexEntryId ); i-- )
       
  1796         {
       
  1797         if ( workingEntry->SetEntry( selection->At( i - 1 ) ) == KErrNone )
       
  1798             {            
       
  1799             CMsvStore* store = workingEntry->ReadStoreL();
       
  1800             CleanupStack::PushL( store );
       
  1801             mmsHeaders->RestoreL( *store );
       
  1802             CleanupStack::PopAndDestroy( store );
       
  1803 
       
  1804             // content location must match 
       
  1805             if ( mmsHeaders->ContentLocation().Compare( aHeaders.ContentLocation() ) == 0 )
       
  1806                 {
       
  1807                 // Identical. This probably means that we have not sent a response yet,
       
  1808                 // and MMSC has sent us a new notification.
       
  1809 
       
  1810 #ifndef _NO_MMSS_LOGGING_
       
  1811                 TMmsLogger::Log( _L("- content locations match") );
       
  1812 #endif
       
  1813                 aDuplicate = workingEntry->Entry().Id();
       
  1814                 }
       
  1815             }
       
  1816         }
       
  1817 
       
  1818     CleanupStack::PopAndDestroy( mmsHeaders );
       
  1819     CleanupStack::PopAndDestroy( selection );
       
  1820     CleanupStack::PopAndDestroy( workingEntry );
       
  1821 
       
  1822     return error;
       
  1823     }
       
  1824 
       
  1825 // ---------------------------------------------------------
       
  1826 // CMmsBaseOperation::FreeNotification
       
  1827 // 
       
  1828 // ---------------------------------------------------------
       
  1829 //
       
  1830 TBool CMmsBaseOperation::FreeNotification( TMsvEntry aEntry, const TUint32 aOperation )
       
  1831     {
       
  1832     if ( aEntry.iMtmData2 & KMmsNewOperationForbidden ||
       
  1833         ( aEntry.iMtmData2 & KMmsOperationFinished &&
       
  1834         !( aEntry.iMtmData2 & KMmsOperationResult ) &&
       
  1835         !( aEntry.iMtmData2 & KMmsStoredInMMBox ) &&
       
  1836         ( aOperation == KMmsOperationFetch || aOperation == KMmsOperationForward )))
       
  1837         {
       
  1838         return EFalse;
       
  1839         }
       
  1840 
       
  1841     return ETrue;
       
  1842     }
       
  1843 
       
  1844 // ---------------------------------------------------------
       
  1845 // CMmsBaseOperation::MarkNotificationOperationFailed
       
  1846 // 
       
  1847 // ---------------------------------------------------------
       
  1848 //
       
  1849 void CMmsBaseOperation::MarkNotificationOperationFailed( TMsvEntry& aEntry )
       
  1850     {
       
  1851     aEntry.iMtmData2 |= KMmsOperationFinished;        // finished
       
  1852     aEntry.iMtmData2 |= KMmsOperationResult;          // failed
       
  1853     aEntry.iMtmData2 &= ~KMmsOperationOngoing;        // operation not active
       
  1854     aEntry.iMtmData2 &= ~KMmsNewOperationForbidden;   // new operation allowed
       
  1855     }
       
  1856 
       
  1857 // ---------------------------------------------------------
       
  1858 // CMmsBaseOperation::MarkNotificationDeletedFromMmbox
       
  1859 // 
       
  1860 // ---------------------------------------------------------
       
  1861 //
       
  1862 void CMmsBaseOperation::MarkNotificationDeletedFromMmbox( TMsvEntry& aEntry )
       
  1863     {
       
  1864     aEntry.iMtmData2 &= ~KMmsStoredInMMBox;         // not in mmbox
       
  1865     aEntry.iMtmData2 &= ~KMmsOperationOngoing;      // operation not active
       
  1866     aEntry.iMtmData2 |= KMmsOperationFinished;      // finished
       
  1867     aEntry.iMtmData2 &= ~KMmsOperationResult;      // successfully 
       
  1868     aEntry.iMtmData2 &= ~KMmsNewOperationForbidden; // new operation allowed
       
  1869     }
       
  1870     
       
  1871 // ---------------------------------------------------------
       
  1872 // CMmsBaseOperation::MarkDuplicateL
       
  1873 // 
       
  1874 // ---------------------------------------------------------
       
  1875 //
       
  1876 void CMmsBaseOperation::MarkDuplicateL( TInt aState, CMsvServerEntry& aServerEntry )
       
  1877     {
       
  1878     // iServerEntry must point to the original notification
       
  1879     // We can put default version here as the headers will be restored immediately anyway
       
  1880     // This is a static function and does not have access to iMmsSettings where the actual
       
  1881     // version is.
       
  1882     // Restoring the headers reads the correct version for the message in question
       
  1883     // Headers are used here only to clear the duplicate id from the headers.
       
  1884     // Other headers are not changed.
       
  1885     CMmsHeaders* mmsHeaders = CMmsHeaders::NewL( KMmsDefaultVersion );
       
  1886     CleanupStack::PushL( mmsHeaders );
       
  1887     CMsvStore* store = aServerEntry.ReadStoreL();
       
  1888     CleanupStack::PushL( store );
       
  1889     mmsHeaders->RestoreL( *store );
       
  1890     CleanupStack::PopAndDestroy( store );
       
  1891     store = NULL;
       
  1892 
       
  1893     TMsvId duplicate = mmsHeaders->RelatedEntry();
       
  1894     if ( duplicate != KMsvNullIndexEntryId )
       
  1895         {
       
  1896         // Clear related entry from the original notification
       
  1897         store = aServerEntry.EditStoreL();
       
  1898         CleanupStack::PushL( store );
       
  1899         mmsHeaders->SetRelatedEntry( KMsvNullIndexEntryId );
       
  1900         mmsHeaders->StoreL( *store );
       
  1901         store->CommitL();
       
  1902         CleanupStack::PopAndDestroy( store );
       
  1903         store = NULL;
       
  1904 #ifndef _NO_MMSS_LOGGING_
       
  1905         TMmsLogger::Log( _L( "- related entry cleared" ) );
       
  1906 #endif
       
  1907         
       
  1908         // Leaves if entry cannot be accessed.
       
  1909         // We are inside a trap already...
       
  1910         CMsvServerEntry* duplicateEntry = aServerEntry.NewEntryL( duplicate );
       
  1911         CleanupStack::PushL( duplicateEntry );
       
  1912         // Mark duplicate
       
  1913         TMsvEntry dupEntry = duplicateEntry->Entry();
       
  1914         switch( aState )
       
  1915             {
       
  1916             case EMmsNotificationOperationFailed:
       
  1917                 MarkNotificationOperationFailed( dupEntry );
       
  1918 #ifndef _NO_MMSS_LOGGING_
       
  1919                 TMmsLogger::Log( _L( "- duplicate marked failed" ) );
       
  1920 #endif
       
  1921                 break;
       
  1922             case EMmsDeletedFromMmbox:
       
  1923                 MarkNotificationDeletedFromMmbox( dupEntry );
       
  1924 #ifndef _NO_MMSS_LOGGING_
       
  1925                 TMmsLogger::Log( _L( "- duplicate marked deleted" ) );
       
  1926 #endif
       
  1927                 break;
       
  1928             default:
       
  1929                 break;    
       
  1930             }
       
  1931         duplicateEntry->ChangeEntry( dupEntry );
       
  1932         CleanupStack::PopAndDestroy( duplicateEntry );
       
  1933 
       
  1934         }
       
  1935     CleanupStack::PopAndDestroy( mmsHeaders );
       
  1936     }
       
  1937     
       
  1938 // ---------------------------------------------------------
       
  1939 // CMmsBaseOperation::MarkNotificationOperationReserved
       
  1940 // ---------------------------------------------------------
       
  1941 //       
       
  1942 void CMmsBaseOperation::MarkNotificationOperationReserved( TMsvEntry& aEntry, 
       
  1943                                                                   const TUint32 aOperation )
       
  1944     {
       
  1945     aEntry.iMtmData2 &= ~KMmsOperationIdentifier;   // clear possible old operation
       
  1946     aEntry.iMtmData2 |= KMmsNewOperationForbidden;  // forbidden   
       
  1947     aEntry.iMtmData2 |= KMmsOperationOngoing;       // operation is active
       
  1948     aEntry.iMtmData2 |= aOperation;                 // operation
       
  1949     aEntry.iMtmData2 &= ~KMmsOperationFinished;     // not finished
       
  1950     aEntry.iMtmData2 &= ~KMmsOperationResult;       // not failed  
       
  1951     }
       
  1952     
       
  1953 // ---------------------------------------------------------
       
  1954 // 
       
  1955 // ---------------------------------------------------------
       
  1956 //       
       
  1957 TBool CMmsBaseOperation::RegisteredL( const TDesC& aApplicationId )
       
  1958     {
       
  1959     TBool registered = EFalse;
       
  1960     // check if application id is registered
       
  1961     CMmsRegisteredApplications* regAppId = CMmsRegisteredApplications::NewL();
       
  1962     CleanupStack::PushL( regAppId );
       
  1963     regAppId->LoadRegisteredApplicationsL();
       
  1964     registered = regAppId->RegisteredL( aApplicationId );
       
  1965     CleanupStack::PopAndDestroy( regAppId );
       
  1966     return registered;
       
  1967     }
       
  1968     
       
  1969 // ---------------------------------------------------------
       
  1970 // CMmsBaseOperation::CommonLogEventInitializationL
       
  1971 // 
       
  1972 // ---------------------------------------------------------
       
  1973 //
       
  1974 void CMmsBaseOperation::CommonLogEventInitializationL(
       
  1975     CMmsHeaders& aMmsHeaders,
       
  1976     TMsvEntry& aEntry )
       
  1977     {
       
  1978     if ( !iLogEvent || !iLogClient )
       
  1979         {
       
  1980         // something wrong with log - cannot do logging
       
  1981         User::Leave( KErrGeneral );
       
  1982         }
       
  1983         
       
  1984     iLogEvent->SetEventType( KLogMmsEventTypeUid );
       
  1985     iLogClient->GetString( iLogString, R_LOG_DIR_OUT );
       
  1986     iLogEvent->SetDirection( iLogString );
       
  1987     iLogEvent->SetDurationType( KLogDurationNone );
       
  1988 
       
  1989     iLogEvent->SetSubject( aEntry.iDescription );
       
  1990     iLogEvent->SetLink( aEntry.Id() );
       
  1991 
       
  1992     iRemoteParties->Reset();
       
  1993     iNumberOfRemoteParties = 0;
       
  1994 
       
  1995     // Get some fields into log entry
       
  1996     TTime now;
       
  1997     // the dates in log must be in universal time, not local time
       
  1998     now.UniversalTime();
       
  1999     iLogEvent->SetTime( now );
       
  2000     // We only log if the sending has been successful.
       
  2001     // We don't generate a log entry if iError not equal to KErrNone
       
  2002     // Therefore the status is always "pending"
       
  2003     iLogClient->GetString( iLogString, R_LOG_DEL_PENDING );
       
  2004     iLogEvent->SetStatus( iLogString );
       
  2005 
       
  2006     // Generate remote party list (pure addresses only)
       
  2007     TInt i;
       
  2008     TPtrC dummy;
       
  2009     // To list
       
  2010     for (i = 0; i < aMmsHeaders.ToRecipients().MdcaCount(); i++)
       
  2011         {
       
  2012         dummy.Set( TMmsGenUtils::PureAddress( aMmsHeaders.ToRecipients().MdcaPoint( i ) ) );
       
  2013         if ( iMmsSettings->LogEmailRecipients() ||
       
  2014             ( dummy.Locate( '@' ) == KErrNotFound ) )
       
  2015             {
       
  2016             iRemoteParties->AppendL( dummy );
       
  2017             iNumberOfRemoteParties++;
       
  2018             }
       
  2019         }
       
  2020     // Cc list
       
  2021     for (i = 0; i < aMmsHeaders.CcRecipients().MdcaCount(); i++)
       
  2022         {
       
  2023         dummy.Set( TMmsGenUtils::PureAddress( aMmsHeaders.CcRecipients().MdcaPoint( i ) ) );
       
  2024         if ( iMmsSettings->LogEmailRecipients() ||
       
  2025             ( dummy.Locate( '@' ) == KErrNotFound ) )
       
  2026             {
       
  2027             iRemoteParties->AppendL( dummy );
       
  2028             iNumberOfRemoteParties++;
       
  2029             }
       
  2030         }
       
  2031     // Bcc list
       
  2032     for (i = 0; i < aMmsHeaders.BccRecipients().MdcaCount(); i++)
       
  2033         {
       
  2034         dummy.Set( TMmsGenUtils::PureAddress( aMmsHeaders.BccRecipients().MdcaPoint( i ) ) );
       
  2035         if ( iMmsSettings->LogEmailRecipients() ||
       
  2036             ( dummy.Locate( '@' ) == KErrNotFound ) )
       
  2037             {
       
  2038             iRemoteParties->AppendL( dummy );
       
  2039             iNumberOfRemoteParties++;
       
  2040             }
       
  2041         }
       
  2042     }
       
  2043     
       
  2044 // start of ROAMING CHECK handling
       
  2045 // ---------------------------------------------------------
       
  2046 // CMmsBaseOperation::RoamingCheck
       
  2047 //
       
  2048 // ---------------------------------------------------------
       
  2049 //
       
  2050 void CMmsBaseOperation::RoamingCheck()
       
  2051     {
       
  2052     // base operation does nothing
       
  2053     // This is just a placeholder
       
  2054     FallThrough();
       
  2055     }
       
  2056     
       
  2057 // ---------------------------------------------------------
       
  2058 // CMmsBaseOperation::GetRoamingState
       
  2059 //
       
  2060 // ---------------------------------------------------------
       
  2061 //
       
  2062 void CMmsBaseOperation::GetRoamingState()
       
  2063     {
       
  2064     // Nothing needs to be done here
       
  2065     }
       
  2066     
       
  2067     
       
  2068     
       
  2069 #ifndef _NO_MMSS_LOGGING_
       
  2070 // ---------------------------------------------------------
       
  2071 // CMmsBaseOperation::LogDateL
       
  2072 //
       
  2073 // ---------------------------------------------------------
       
  2074 void CMmsBaseOperation::LogDateL( const TTime& aDate )
       
  2075     {
       
  2076     TBuf<KMmsDateBufferLength> dateString;
       
  2077     aDate.FormatL(dateString,(_L("%*E%*D%X%*N%Y %1 %2 '%3")));
       
  2078     TMmsLogger::Log( _L(" - date %S"), &dateString );
       
  2079     aDate.FormatL(dateString,(_L("%-B%:0%J%:1%T%:2%S%:3%+B")));
       
  2080     TMmsLogger::Log( _L(" - time %S"), &dateString );
       
  2081     }
       
  2082     
       
  2083 // ---------------------------------------------------------
       
  2084 // CMmsBaseOperation::LogNetworkFormatDateL
       
  2085 //
       
  2086 // ---------------------------------------------------------
       
  2087 void CMmsBaseOperation::LogNetworkFormatDateL( const TInt64& aDateInSeconds )
       
  2088     {
       
  2089     TBuf<KMmsDateBufferLength> dateString;
       
  2090     TMmsLogger::Log( _L(" - %d seconds from 1.1.1970 (UTC)"), aDateInSeconds );
       
  2091     TTime time = TTime( KMmsYear1970String ) +
       
  2092         TTimeIntervalMicroSeconds( aDateInSeconds * KMmsMillion );
       
  2093     time.FormatL(dateString,(_L("%*E%*D%X%*N%Y %1 %2 '%3")));
       
  2094     TMmsLogger::Log( _L(" - date %S"), &dateString );
       
  2095     time.FormatL(dateString,(_L("%-B%:0%J%:1%T%:2%S%:3%+B")));
       
  2096     TMmsLogger::Log( _L(" - time %S"), &dateString );
       
  2097     }
       
  2098     
       
  2099 #else
       
  2100 // ---------------------------------------------------------
       
  2101 // CMmsBaseOperation::LogDateL
       
  2102 //
       
  2103 // ---------------------------------------------------------
       
  2104 void CMmsBaseOperation::LogDateL( const TTime& )
       
  2105     {
       
  2106     }
       
  2107     
       
  2108 // ---------------------------------------------------------
       
  2109 // CMmsBaseOperation::LogNetworkFormatDateL
       
  2110 //
       
  2111 // ---------------------------------------------------------
       
  2112 void CMmsBaseOperation::LogNetworkFormatDateL( const TInt64& )
       
  2113     {
       
  2114     }
       
  2115 #endif
       
  2116     
       
  2117     
       
  2118 // ========================== OTHER EXPORTED FUNCTIONS =========================
       
  2119 
       
  2120 //  End of File