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