/*
* Copyright (c) 2002-2004 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  mmsconninit implementation
*
*/


   
// INCLUDE FILES   
#include <in_sock.h>
#include <es_enum.h>
#include <e32property.h>
#include <sacls.h>
#include <mpmpropertydef.h> 

// USERINCLUDE FILES
#include "mmsconninit.h"

// EXTERNAL DATA STRUCTURES
// EXTERNAL FUNCTION PROTOTYPES  
// CONSTANTS
const TInt32 KMmsShortTimeout = 30; // seconds
// Interval must be long enough to give the connection time to recover
const TInt32 KMmsRetryInterval = 10; // seconds
const TInt KMmsSecondsToMilliseconds = 1000000;
// Only one retry - if that does not work, better reschedule the operation normally
const TInt KMmsMaxRetryCount = 1;
const TInt KMaxProxyPortLength = 6;
_LIT( KHttpSchemePart1, "http" );
_LIT( KHttpSchemePart2, "://" );
const TInt KMmsScheme1Length = 4;
const TInt KMmsHTTPSchemeLength = 7;


// MACROS
// LOCAL CONSTANTS AND MACROS
// MODULE DATA STRUCTURES
// LOCAL FUNCTION PROTOTYPES
// ============================== LOCAL FUNCTIONS ==============================
// ============================== MEMBER FUNCTIONS =============================

// -----------------------------------------------------------------------------
// CMmsConnectionInitiator
// -----------------------------------------------------------------------------
//
CMmsConnectionInitiator::CMmsConnectionInitiator() : 
    CActive( EPriorityStandard )
    {   
    }

// -----------------------------------------------------------------------------
// ConstructL
// -----------------------------------------------------------------------------
//
void CMmsConnectionInitiator::ConstructL()
    {
    CActiveScheduler::Add( this );
    iTimerRunning = EFalse;
    }

// -----------------------------------------------------------------------------
// NewL
// -----------------------------------------------------------------------------
//
EXPORT_C CMmsConnectionInitiator* CMmsConnectionInitiator::NewL()
    {
    CMmsConnectionInitiator* self = new ( ELeave ) CMmsConnectionInitiator;
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    #ifdef _MMSCONNINIT_LOGGING_
    TMmsConnInitLogger::Log( _L("MmsConnInit constructed ") );
    #endif
    return self;
    }
    
// -----------------------------------------------------------------------------
// ~CMmsConnectionInitiator
// -----------------------------------------------------------------------------
//
CMmsConnectionInitiator::~CMmsConnectionInitiator()
    {
    // cancel closes our timer if it is running
    Cancel();
    // iConnection, iClientStatus and iArray are owned by caller
    
    // Just to be sure the Access point property goes, delete it
    // Never mind the error - this is the best effort.
    // If it does not work, what can we do. Question mark. (To avoid "worrying commets")
#ifdef _MMSCONNINIT_LOGGING_
    TMmsConnInitLogger::Log( _L("deleting KMPMPropertyKey") );    
#endif      
    RProperty::Delete( KMPMCathegory, KMPMPropertyKeyMMS );
    
    #ifdef _MMSCONNINIT_LOGGING_
    TMmsConnInitLogger::Log( _L("MmsConnInit destroyed ") );
    #endif
    }

// -----------------------------------------------------------------------------
// ConnectL
// -----------------------------------------------------------------------------
//
EXPORT_C void CMmsConnectionInitiator::ConnectL( 
    RConnection&  aConnection,
    CArrayFixFlat<TUint32>& aAccessPointArray, 
    TRequestStatus& aStatus )
    {
#ifdef _MMSCONNINIT_LOGGING_
    TMmsConnInitLogger::Log( _L("MmsConnInit::ConnectL") );
#endif
    iClientStatus  = &aStatus;
    iConnection    = &aConnection;
    iArray         = &aAccessPointArray;
    *iClientStatus = KRequestPending;
    iIndex = 0;
    iTimerRunning = EFalse;
    iRetryCount = 0;

    // No reason to continue if the array is empty
    if( aAccessPointArray.Count() == 0 )
        {
        User::RequestComplete( iClientStatus, KErrArgument );
        return; 
        }     
    
    if ( !CheckNetworkL() )
        {
        User::RequestComplete( iClientStatus, KErrCouldNotConnect );
        return;
        }
 
    // Let's not start the AO if we do not find IAP
    for( iIndex = 0; iIndex < iArray->Count(); iIndex++ )
        {
        TUint32 ap; // IAP to be resolved
        // index is safe
        if( ( FindIapL( iArray->At( iIndex ), ap ) ) )
            {
            // Let's override the preferences
            iPrefs.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);            
            //Start the connection
            StartConnectionL( ap );
            iStartTime.UniversalTime();
            SetActive();
            return;  
            }           
        // IAP not found but let's keep on looping
        }    
    //We looped through the array and did not succeed
    //We do not have any error value in the iStatus because we 
    //did not even try to connect
    User::RequestComplete( iClientStatus, KErrCouldNotConnect );  
    return;
    }

// -----------------------------------------------------------------------------
// GetParametersL
// -----------------------------------------------------------------------------
//
EXPORT_C void CMmsConnectionInitiator::GetParametersL( 
    TUint32 aAccessPointLink,
    TUint32& aAccessPoint,
    HBufC*& aServerUri,
    TBool& aProxyUsed,
    HBufC8*& aProxyAddress )
    {
    // Every function reading the commsDB are trapped because 
    // they may leave if the field is empty. We still may be 
    // able to continue browsing the DB further.
    // Exception: Functions reading long text are not trapped 
    // because they allocate memory.

#ifdef _MMSCONNINIT_LOGGING_    
    TMmsConnInitLogger::Log( _L("MmsConnInit::GetParametersL") );
#endif

    // Initialise OUT parameters
    aServerUri = NULL;
    aAccessPoint = 0;
    aProxyUsed = EFalse;
    aProxyAddress = NULL;
    
    // Initialise used variables
    TInt error = KErrNone;
    TUint32 num32Value = 0;
    TBuf <KCommsDbSvrMaxFieldLength> textValue; 
    TInt length = 0;
    CCommsDbTableView* view = NULL;

    // Connect to Database server and CommDb
    CCommsDatabase* db = CCommsDatabase::NewL( EDatabaseTypeUnspecified );
    CleanupStack::PushL( db );

    // Start from WAP_ACCESS_POINT table -> opening view to it
    view = db->OpenViewMatchingUintLC(
        TPtrC( WAP_ACCESS_POINT ),
        TPtrC( COMMDB_ID ), 
        aAccessPointLink );

    // If no record for 'aAccessPointLink' there's nothing to look for
    if( view->GotoFirstRecord() != KErrNone )
        {
        CleanupStack::PopAndDestroy( view );
        CleanupStack::PopAndDestroy( db );
        return;
        }

    // Get aServerUri (WAP_START_PAGE in CommDb)
    // ReadColumnLengthL only leaves if the column does not exist at all -
    // that means that the database structure is totally wrong, and we can't continue
    view->ReadColumnLengthL( TPtrC( WAP_START_PAGE ), length );
    // ReadLongTextL only leaves if the column does not exist in the table
    // or we are out of memory.
    aServerUri = view->ReadLongTextLC( TPtrC( WAP_START_PAGE ) );
    // If the function did not leave, we have aServerUri on the cleanup stack
    // It's length may be 0, but the pointer itself is not NULL
    if( length != 0 )
        {
        CheckWapStartPageL( aServerUri ); // tries to ensure proper syntax
        }
        
    // Get link to bearer
    // This function only leaves if the column does not exist in the table
    // This means the structure of the database is incorrect, and we cannot continue
    view->ReadTextL( TPtrC( WAP_CURRENT_BEARER ), textValue );
    
    // view must be deleted, but it is not on top of the CleanupStack
    CleanupStack::Pop( aServerUri );
    CleanupStack::PopAndDestroy( view );
    view = NULL;
    
    if( textValue.Length() == 0 )
        {
        // Impossible to continue because bearer (textValue) is needed to browse further
        CleanupStack::PopAndDestroy( db );
        return;
        }

    // Put aServerUri back on the cleanup stack
    CleanupStack::PushL( aServerUri );

    // Create new view to bearer table
    view = db->OpenViewMatchingUintLC( 
        textValue, 
        TPtrC( WAP_ACCESS_POINT_ID ), 
        aAccessPointLink );
    
    // There should be only one record with aAccessPointLink
    if( view->GotoFirstRecord() != KErrNone )
        {
        // If no record for 'aAccessPointLink' there's nothing to look for
        CleanupStack::PopAndDestroy( view ); // view
        CleanupStack::Pop( aServerUri );
        CleanupStack::PopAndDestroy( db );
        return;
        }

    // Get AccessPoint
    // This function leaves if the column has NULL value
    TRAP( error, view->ReadUintL( TPtrC( WAP_IAP ), num32Value ) );  
    
    // Current view not needed any more
    CleanupStack::PopAndDestroy( view ); // view
    view = NULL;
    
    if( error == KErrNone )
        {
        aAccessPoint = num32Value;
        }
    else
        {
        CleanupStack::Pop( aServerUri );
        CleanupStack::PopAndDestroy( db );
        return;
        }
    
    // Create view to IAP table
    view = db->OpenViewMatchingUintLC( TPtrC( IAP ), TPtrC( COMMDB_ID ), aAccessPoint );
    
    // There should be only one record with aAccessPoint
    if( view->GotoFirstRecord() != KErrNone )
        {
        // no record found
        CleanupStack::PopAndDestroy( view ); // view
        CleanupStack::Pop( aServerUri );
        CleanupStack::PopAndDestroy( db );
        aAccessPoint = 0; // Client will know that the procedure failed
        return;        
        }
        
    // Get servicetype and -identifier
    TRAP( error,
        {
        view->ReadTextL( TPtrC( IAP_SERVICE_TYPE ), textValue ); // read service type
        view->ReadUintL( TPtrC( IAP_SERVICE ), num32Value ); // read service identifier
        });
    if( error )
        {
        // Leave occurred, cleaning up
        CleanupStack::PopAndDestroy( view ); // view
        CleanupStack::Pop( aServerUri );
        CleanupStack::PopAndDestroy( db );
        aAccessPoint = 0; // Client will know that the procedure failed
        return;        
        }

    // Current view not needed any more
    CleanupStack::PopAndDestroy( view );
    view = NULL;
    
    // Create view to Proxy table
    view = db->OpenViewOnProxyRecordLC( num32Value, textValue );
    // There should be only one record matching service identifier and service type
    if( view->GotoFirstRecord() != KErrNone )
        {
        CleanupStack::PopAndDestroy( view ); // view
        CleanupStack::Pop( aServerUri );
        CleanupStack::PopAndDestroy( db );
        return;
        }
                
    // Get information whether proxy is used or not
    TRAP( error, view->ReadBoolL( TPtrC( PROXY_USE_PROXY_SERVER ), aProxyUsed ) );
    if ( error != KErrNone )
        {
        CleanupStack::PopAndDestroy( view ); // view
        CleanupStack::Pop( aServerUri );
        CleanupStack::PopAndDestroy( db );
        return;
        }
    
    // If proxy is to be used, get the related information
    if( aProxyUsed )
    	{
        // Get proxy port number
        TRAP( error, view->ReadUintL( TPtrC( PROXY_PORT_NUMBER ), num32Value ) );
        if( error != KErrNone )
            {
            CleanupStack::PopAndDestroy( view ); // view
            CleanupStack::Pop( aServerUri );
            CleanupStack::PopAndDestroy( db );
            return;
            }
            
        if( num32Value > KMaxTUint16 )
            {
            // Proxy port has too big value, access point is invalid
            CleanupStack::PopAndDestroy( view ); // view
            CleanupStack::Pop( aServerUri );
            CleanupStack::PopAndDestroy( db );
            
            User::Leave( KErrTooBig );
            }

    	// Following LIT is the proxy port number beginning with ":"
        _LIT( KProxyPort,":%d" );
        HBufC* tempProxyPort = NULL;  
        HBufC* tempProxyServerName = NULL;
        tempProxyServerName = view->ReadLongTextLC( TPtrC( PROXY_SERVER_NAME ) );
        tempProxyServerName->Des().Trim(); // remove possible spaces
        
        tempProxyPort = HBufC::NewLC( KMaxProxyPortLength );
        TPtr ptr2( tempProxyPort -> Des() );
        ptr2.Format( KProxyPort,num32Value ); 
        
        // Create a TPtr object to aProxyAddress
        // Proxy address must always be us-ascii or we are in trouble.
        TPtr ptr( tempProxyServerName -> Des() );
        aProxyAddress = HBufC8::NewLC(
            ( tempProxyServerName->Length() ) + ( tempProxyPort->Length() ) ); 
        aProxyAddress->Des().Copy( ptr );
        aProxyAddress->Des().Append( ptr2 );
        CleanupStack::Pop( aProxyAddress );
        CleanupStack::PopAndDestroy( tempProxyPort );
        CleanupStack::PopAndDestroy( tempProxyServerName );
        } // aProxyUsed
        
	CleanupStack::PopAndDestroy( view ); // view
	view = NULL;
    CleanupStack::Pop( aServerUri );
    CleanupStack::PopAndDestroy( db );

#ifdef _MMSCONNINIT_LOGGING_
    TPtr temp = aServerUri->Des();
    TMmsConnInitLogger::Log( _L("aServerUri: %S"), &temp );
    TMmsConnInitLogger::Log( _L("aAccessPoint: %d"), aAccessPoint ); 
    TMmsConnInitLogger::Log( _L("aProxyUsed: %d"), aProxyUsed );
    /*
    if( aProxyAddress != NULL )
        {
        TMmsConnInitLogger::Log( _L("aProxyAddress: %S"), &temp );
        }
    */        
#endif
    }
    
// -----------------------------------------------------------------------------
// CheckNetworkL
// -----------------------------------------------------------------------------
//
TBool CMmsConnectionInitiator::CheckNetworkL()
    {
#ifdef __WINS__
    // Emulator has network always "available"
    return ETrue;
#endif // __WINS__

    TInt value = 0;
    TInt error = RProperty::Get( KUidSystemCategory, KUidNetworkStatus.iUid, value );
    User::LeaveIfError( error );
    
#ifdef _MMSCONNINIT_LOGGING_
    if ( value == ESANetworkAvailable )
        {
        TMmsConnInitLogger::Log( _L("Network available") );
        }
    else
        {
        TMmsConnInitLogger::Log( _L("Network NOT available, value = %d"), value );
        }
#endif

    return ( value == ESANetworkAvailable );
    }

// -----------------------------------------------------------------------------
// CMmsConnectionInitiator::CheckWapStartPageL
// 
// Private fuction used only by GetParametersL. Made just for splitting too big
// GetParameters function. 
// Adds http scheme in the beginning of wap start page if it is missing. It does
// not add it into comms database. 
// 
// -----------------------------------------------------------------------------
//
void CMmsConnectionInitiator::CheckWapStartPageL(HBufC*& aUri)
    {
     
    aUri->Des().Trim();  // remove spaces 
     
    if ( aUri->Find(KHttpSchemePart2) > 0)
        {
        ;// OK, nothing needs to be done;
        }
    else if (aUri->Find(KHttpSchemePart2) == 0)
        {
        // NOK, adding 'KHttpSchemePart1' to the beginning of the uri
        HBufC* tmp = HBufC::NewMaxLC( aUri->Length() + KMmsScheme1Length );
        tmp->Des().Copy( KHttpSchemePart1() );
        tmp->Des().Append( aUri->Des() );
        CleanupStack::Pop( tmp );
        CleanupStack::PopAndDestroy( aUri );
        aUri = tmp;
        CleanupStack::PushL(aUri);  
             
        }
    else // HttpScheme2 not found in this case
        {
        // NOK, adding 'KHttpScheme' to the beginning of the uri
        
        HBufC* tmp = HBufC::NewMaxLC( aUri->Length() + KMmsHTTPSchemeLength );
        tmp->Des().Copy( KHttpSchemePart1() );
        tmp->Des().Append( KHttpSchemePart2() );
        tmp->Des().Append( aUri->Des() );

        CleanupStack::Pop( tmp );
        CleanupStack::PopAndDestroy( aUri );
        aUri = tmp;
        CleanupStack::PushL(aUri);        
        }
    }

// -----------------------------------------------------------------------------
// CMmsConnectionInitiator::FindIapL
// WAP Acces Point is given as in-parameter and IAP is 
// retruned as out-parameter
// Return value is EFalse if something goes wrong
// Leavings are trapped in case of error in reading CommsDb
// -----------------------------------------------------------------------------
//
TBool CMmsConnectionInitiator::FindIapL( TUint32 aWapAP, TUint32& aIap ) 
    {
    aIap = 0;
    TUint32 num32Value = 0;
    TInt error = KErrNone;
    CCommsDatabase* db = CCommsDatabase::NewL( EDatabaseTypeUnspecified );
    CleanupStack::PushL( db );
    CCommsDbTableView* view;

    TBuf<KCommsDbSvrMaxFieldLength> textValue; // Max limit defined by database

    // Start from the WAP access point table
    // If there is no WAP access point table, the function leaves.
    view=db->OpenViewMatchingUintLC( 
        TPtrC( WAP_ACCESS_POINT ),
        TPtrC( COMMDB_ID ), 
        aWapAP );
    if ( view->GotoFirstRecord() != KErrNone )
        {
        CleanupStack::PopAndDestroy( view );
        CleanupStack::PopAndDestroy( db );
        return EFalse;
        }

    // Link to bearer table
    TRAP( error, view->ReadTextL( TPtrC( WAP_CURRENT_BEARER ), textValue ) );
    if ( error != KErrNone)
        {
        CleanupStack::PopAndDestroy( view );
        CleanupStack::PopAndDestroy( db );
        return EFalse;
        }
    
    CleanupStack::PopAndDestroy( view ); // view
    view = NULL;
    
    // Found WAP access point. Now we need the WAP bearer
    view=db->OpenViewMatchingUintLC( textValue, TPtrC( WAP_ACCESS_POINT_ID ), 
        aWapAP );
    if ( view->GotoFirstRecord() != KErrNone )
        {
        CleanupStack::PopAndDestroy( view );
        CleanupStack::PopAndDestroy( db );
        return EFalse;
        }
    
    //Let's trap the leave if there is no IAP and try to continue normally
    TRAP( error, view->ReadUintL( TPtrC( WAP_IAP ), num32Value ) );
    CleanupStack::PopAndDestroy( view );
    CleanupStack::PopAndDestroy( db );
    if ( error == KErrNone )
        {
        aIap = num32Value;
        return ETrue;
        } 
    else
        {  
        return EFalse;
        }
    }

// -----------------------------------------------------------------------------
// CMmsConnectionInitiator::StartConnectionL
// Checks if there is already connections open and checks if the 
// connection could be reused or not.
// -----------------------------------------------------------------------------
//
void CMmsConnectionInitiator::StartConnectionL(TUint32 aIap)
    {
#ifdef _MMSCONNINIT_LOGGING_    
    TMmsConnInitLogger::Log( _L("CMmsConnectionInitiator::StartConnectionL") );
#endif
    TUint count; 
    TPckgBuf<TConnectionInfo> connInfo;
    TUint i;
    TUint32 iap;
    HBufC* gprsApn1 = NULL; 
    HBufC* gprsApn2 = NULL; 
    TUint32 pdpType1 = 0;    
    TUint32 pdpType2 = 0;      
    iap = aIap;

#ifdef _MMSCONNINIT_LOGGING_    
    TMmsConnInitLogger::Log( _L("iConnection->EnumerateConnections") );
#endif   
    iConnection->EnumerateConnections( count );

#ifdef _MMSCONNINIT_LOGGING_    
    TMmsConnInitLogger::Log( _L("Connection count: %d"),count);
#endif
   
    if ( count > 0 && FindGprsParametersL( aIap,pdpType1,gprsApn1 ) )
        {
        CleanupStack::PushL(gprsApn1);
        for ( i=1; i<=count; i++ )
            {         
            if ( gprsApn2 )
                {
                delete gprsApn2;
                gprsApn2 = NULL;
                } 
#ifdef _MMSCONNINIT_LOGGING_    
    TMmsConnInitLogger::Log( _L("iConnection->GetConnectionInfo ") );
#endif 
            iConnection->GetConnectionInfo( i,connInfo );
#ifdef _MMSCONNINIT_LOGGING_    
    TMmsConnInitLogger::Log( _L("FindGprsParametersL ") );
#endif
            if ( FindGprsParametersL( connInfo().iIapId,pdpType2,gprsApn2 ) 
                && pdpType1 == pdpType2 
                && *gprsApn1 == *gprsApn2 ) 
                {
#ifdef _MMSCONNINIT_LOGGING_    
    TMmsConnInitLogger::Log( _L("APN MATCH !!!!!!!") );
#endif
                iap = connInfo().iIapId;  
                }
            }
        }    
    if ( gprsApn2 )
        {
        delete gprsApn2;
        }
    if ( gprsApn1 )
        {
        CleanupStack::PopAndDestroy( gprsApn1 );
        }

    iPrefs.SetIapId( iap );
#ifdef _MMSCONNINIT_LOGGING_    
    TMmsConnInitLogger::Log( _L("iConnection->Start ") );
#endif
    TInt error = RProperty::Define( KMPMCathegory, KMPMPropertyKeyMMS, KMPMPropertyTypeMMS ); 
    if ( error == KErrNone || error == KErrAlreadyExists )
        {
        // If the setting of the value does not succeed, a disconnect dialog
        // may be displayed - but there is nothing we can do about it.
        // We try our best.
#ifdef _MMSCONNINIT_LOGGING_    
        TMmsConnInitLogger::Log( _L("setting KMPMProperty key to %d "), iap );
#endif
        error = RProperty::Set( KMPMCathegory, KMPMPropertyKeyMMS, iap );
        }
    // iConnection cannot be active when we come here.
    // And it is not possible to ask ir RConnection is active
    iConnection->Start( iPrefs, iStatus );
    return;
    }

// -----------------------------------------------------------------------------
// CMmsConnectionInitiator::FindGprsParametersL
// Solves PDP type and GPRS Access Point. 
// -----------------------------------------------------------------------------

TBool CMmsConnectionInitiator::FindGprsParametersL(
    TUint32 aIap, TUint32& aPdpType, HBufC*& aGprsApn )
    {
#ifdef _MMSCONNINIT_LOGGING_    
    TMmsConnInitLogger::Log( _L("CMmsConnectionInitiator::FindGprsParameters") );
    TMmsConnInitLogger::Log( _L("IAP to analyze: %d"),aIap);
#endif
    TUint32 service=0;
    TBuf  <KCommsDbSvrMaxFieldLength> textValue; 
    CCommsDbTableView* view = NULL; 

    CCommsDatabase* db = CCommsDatabase::NewL( EDatabaseTypeUnspecified );
    CleanupStack::PushL( db ); 
    view = db->OpenViewMatchingUintLC( TPtrC( IAP ), TPtrC( COMMDB_ID ), aIap );
    if ( view->GotoFirstRecord() == KErrNone )
        {
        view->ReadTextL( TPtrC( IAP_SERVICE_TYPE ), textValue );
#ifdef _MMSCONNINIT_LOGGING_  
        TMmsConnInitLogger::Log (_L("IAP_SERVICE_TYPE: "));
        TMmsConnInitLogger::Log(textValue); 
#endif
        if ( textValue.Compare( TPtrC( OUTGOING_GPRS ) ) != 0 )
            {
            CleanupStack::PopAndDestroy( view );
            CleanupStack::PopAndDestroy( db );
            return EFalse;
            }
        view->ReadUintL( TPtrC( IAP_SERVICE ), service );
        }
    else
        {
        CleanupStack::PopAndDestroy( view );
        CleanupStack::PopAndDestroy( db );
        return EFalse;
        }
    CleanupStack::PopAndDestroy( view ); //view
    view = NULL;

    view = db->OpenViewMatchingUintLC( textValue, TPtrC( COMMDB_ID ), service );
    if ( view->GotoFirstRecord() == KErrNone )
        {
        aGprsApn = view->ReadLongTextLC( TPtrC( GPRS_APN ) );
        view->ReadUintL( TPtrC( GPRS_PDP_TYPE ),aPdpType );               
#ifdef _MMSCONNINIT_LOGGING_ 
        TMmsConnInitLogger::Log( _L("GPRS_APN: "));    
        TMmsConnInitLogger::Log(aGprsApn->Des()); 
        TMmsConnInitLogger::Log( _L("aPdpType: %d"),aPdpType);
#endif   
        CleanupStack::Pop( aGprsApn );
        CleanupStack::PopAndDestroy( view );
        CleanupStack::PopAndDestroy( db );
        }
    else
        {
        CleanupStack::PopAndDestroy( view );
        CleanupStack::PopAndDestroy( db );
        return EFalse;
        }
    return ETrue;
    }

// -----------------------------------------------------------------------------
// RunL
// -----------------------------------------------------------------------------
//
void CMmsConnectionInitiator::RunL()
    {
    // immediately release the access point
#ifdef _MMSCONNINIT_LOGGING_
    TMmsConnInitLogger::Log( _L("deleting KMPMPropertyKeyMMS") );    
#endif      
    RProperty::Delete( KMPMCathegory, KMPMPropertyKeyMMS );
    
    iConnection->Progress( iProgress );
#ifdef _MMSCONNINIT_LOGGING_     
    TMmsConnInitLogger::Log( _L("MmsConnInit::RunL, status: %d"), iStatus.Int() );    
    TMmsConnInitLogger::Log( _L(" - progress stage: %d, progress error: %d"), iProgress.iStage, iProgress.iError );
#endif      

    // In error situation, set iStatus to the error
    // error form iProgress overrides status only if status is KErrNone
    // The behavior of lower level components has changed.
    // We are trying to adjust our behavior to the new situation.
    
    if ( iTimerRunning )
        {
        // own timer timed out
        iTimer.Close();
        iStatus = KErrCompletion;
        iTimerRunning = EFalse;
        }
    
    if ( iStatus.Int() == KErrNone )
        {
        iStatus = iProgress.iError;
        }
        
    if ( iStatus.Int() == KErrNotFound || iStatus.Int() == KErrGeneral )
        {
        // We should never pass KErrNotFound upwards as it will
        // prevent retry loop, and might prevent fetching altogether.
        // KErrGeneral does not mean anything, so we try if we can find
        // a better error code from progress.
        if ( iProgress.iError < KErrGeneral )
            {
            // We have some error code in iProgress, and it is not
            // KErrNotFound or KErrGeneral
            iStatus = iProgress.iError;
            }
        else
            {
            // This is better than KErrNotFound.
            // It does not tell why the connection was not created,
            // but at least it leads to retry loop
            iStatus = KErrCouldNotConnect;
            }
        }

    if( iStatus.Int() == KErrNone )
        {
        // iConnection.start completes with no error
        // In this succesfull case we set the client status
        // to index+1 of the AP array
#ifdef _MMSCONNINIT_LOGGING_ 
        TMmsConnInitLogger::Log( _L("- Connected") );
#endif
        User::RequestComplete( iClientStatus, ( iIndex + 1 ) );    
        return;
        }
    else // status not equal to KErrNone
        { 
        TTime now;
        now.UniversalTime();
        TTimeIntervalSeconds timeout = 0;
        TInt overflow;
        if ( iStatus.Int() == KErrTimedOut )
            {
#ifdef _MMSCONNINIT_LOGGING_ 
            TMmsConnInitLogger::Log( _L("- Timed out") );
#endif
            overflow = now.SecondsFrom( iStartTime, timeout );
            if ( overflow == KErrNone &&
                timeout.Int() < KMmsShortTimeout &&
                iRetryCount < KMmsMaxRetryCount )
                {
                // worth retrying after a few seconds
                iRetryCount++;
                TInt error = iTimer.CreateLocal();
                if ( error == KErrNone )
                    {
                    // timer wants microseconds
                    // iTimer cannot be running as it was closed just a while ago
                    // And we just said "CreateLocal()" so this is a brand new timer.
                    iTimer.After( iStatus, KMmsRetryInterval * KMmsSecondsToMilliseconds );
                    iTimerRunning = ETrue;
                    SetActive();
                    return;
                    }
                }
            }
        
#ifdef _MMSCONNINIT_LOGGING_ 
        TMmsConnInitLogger::Log( _L("- Not connected") );
#endif
        // Because we now completed with an error we must re-issue the 
        // request if there are still items in the array
        TUint32 ap; //IAP to be resolved
        if ( iStatus != KErrCompletion )
            {
            // KErrCompletion means our timer completed
            // and we must retry the same access point.
            // If we have some other error, we must try next access point
            iIndex++;
            }
        else
            {
#ifdef _MMSCONNINIT_LOGGING_ 
            TMmsConnInitLogger::Log( _L("- Timer completed - retry %d"), iRetryCount );
#endif
            }
        for( iIndex = iIndex; iIndex < iArray->Count(); iIndex++ )
            {
            // index is safe
            if( ( FindIapL( iArray->At( iIndex ), ap ) ) )
                {
                StartConnectionL( ap );
                SetActive();
                return;
                }      
            // Loop until AP found
            }   
        // Looped through the whole array with no success
        User::RequestComplete( iClientStatus, iStatus.Int() );
        return;
        }
    } 
    
// ---------------------------------------------------------
// 
// ---------------------------------------------------------
//
TInt CMmsConnectionInitiator::RunError(TInt aError)
    {
    User::RequestComplete( iClientStatus, aError );
    return KErrNone;
    }
    
// -----------------------------------------------------------------------------
// CMmsConnectionInitiator::DoCancel
// Cancels any outstanding request
// -----------------------------------------------------------------------------
//
void CMmsConnectionInitiator::DoCancel()
    {
    //This function is called by Cancel() if there is an
    //request outstanding.
#ifdef _MMSCONNINIT_LOGGING_
    TMmsConnInitLogger::Log( _L("deleting KMPMPropertyKeyMMS") );    
#endif      
    RProperty::Delete( KMPMCathegory, KMPMPropertyKeyMMS );
    if ( iTimerRunning )
        {
        iTimer.Cancel();
        iTimer.Close();
        iTimerRunning = EFalse;
        }
    iConnection->Close();
    User::RequestComplete( iClientStatus, KErrCancel );
#ifdef _MMSCONNINIT_LOGGING_ 
    TMmsConnInitLogger::Log( _L("MmsConnInit cancelled") );
#endif
    }

// -----------------------------------------------------------------------------
#ifdef _MMSCONNINIT_LOGGING_
const TInt KLogBufferLength = 256;
_LIT(KLogDir, "mmss");
_LIT(KLogFile, "mmsconninit.txt");

void TMmsConnInitLogger::Log(TRefByValue<const TDesC> aFmt,...)
    {
    VA_LIST list;
    VA_START(list, aFmt);

    // Print to log file
    TBuf<KLogBufferLength> buf;
    buf.FormatList(aFmt, list);

    // Write to log file
    RFileLogger::Write(KLogDir, KLogFile, EFileLoggingModeAppend, buf);
    }
#endif    

// =========================== OTHER EXPORTED FUNCTIONS ========================

//  End of File  
