locationmanager/ReverseGeocode/src/clientengine.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 19 Aug 2010 10:20:41 +0300
branchRCL_3
changeset 19 b73252188534
permissions -rw-r--r--
Revision: 201031 Kit: 201033

/*
* Copyright (c) 2006-2009 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: Implementation of HTTP Client Engine.
*/

//Symbian headers
#include <http.h>
#include <commdbconnpref.h>
#include <connpref.h>
#include <extendedconnpref.h>
#include <commdb.h>
#include <etel3rdparty.h>                // voice call notification
#include <mmtsy_names.h>                 // kmmtsymodulename
#include "locationmanagerdebug.h"
#include "clientengine.h"

// Used user agent for requests
_LIT8(KUserAgent, "SimpleClient 1.0");

// This client accepts all content types.
_LIT8(KAccept, "*/*");

// ----------------------------------------------------------------------------
// CClientEngine::NewL()
// ----------------------------------------------------------------------------
CClientEngine* CClientEngine::NewL( MClientObserver& aObserver)
    {
    LOG("CClientEngine::NewL ,begin");
    CClientEngine* self = CClientEngine::NewLC( aObserver);
    CleanupStack::Pop( self );
    return self;
    }

// ----------------------------------------------------------------------------
// CClientEngine::NewLC()
// ----------------------------------------------------------------------------
CClientEngine* CClientEngine::NewLC(MClientObserver& aObserver)
    {
    LOG("CClientEngine::NewLC ,begin");
    CClientEngine* self = new ( ELeave ) CClientEngine( aObserver);
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

// ----------------------------------------------------------------------------
// CClientEngine::CClientEngine()
// ----------------------------------------------------------------------------
CClientEngine::CClientEngine( MClientObserver& aObserver): 
                                CActive( CActive::EPriorityStandard ),
                                iObserver( aObserver ),
                                iConnectionSetupDone( EFalse ),
                                iPrevProfileId( -1 ),
                                iMobility(NULL),
                                iTransactionOpen( EFalse ),
                                iUri(NULL)
    {
    }

// ----------------------------------------------------------------------------
// CClientEngine::~CClientEngine()
// ----------------------------------------------------------------------------
CClientEngine::~CClientEngine()
    {
    LOG("CClientEngine::~CClientEngine ,begin");
    Cancel();

    if ( iTransactionOpen )
        {
        iTransaction.Close();
        iTransactionOpen = EFalse;
        }
    
    if ( iMobility )
        {
        iMobility->Cancel();
        }
    delete iMobility;
    iMobility = NULL;
    
    if(iConnectionSetupDone)
        {
        iSession.Close();
        iConnection.Close();
        iSocketServ.Close();
        }
    delete iUri;
    iUri = NULL;
   
	iCmManager.Close();

    
    // DON'T cose RMobilePhone object

	LOG("CClientEngine::~CClientEngine ,end");
    }

// ----------------------------------------------------------------------------
// CClientEngine::ConstructL()
// ----------------------------------------------------------------------------
void CClientEngine::ConstructL()
  {
  LOG("CClientEngine::ConstructL ,begin");
  CActiveScheduler::Add(this);
  iCmManager.OpenL();
  LOG("CClientEngine::ConstructL ,end");
  }

// ----------------------------------------------------------------------------
// CClientEngine::CloseConnection()
// ----------------------------------------------------------------------------
void CClientEngine::CloseConnection()
    {
    LOG("CClientEngine::CloseConnection ,begin" );
    if ( iTransactionOpen )
        {
        iTransaction.Close();
        iTransactionOpen = EFalse;
        }
    
    if ( iMobility )
        {
		iMobility->Cancel();
		delete iMobility;
		iMobility = NULL;
        }

    if(iConnectionSetupDone)
        { 
        iSession.Close();
        iConnection.Close();
        iSocketServ.Close();  
           
        iConnectionSetupDone = EFalse;
        }
	LOG("CClientEngine::CloseConnection ,end");
    }


// ----------------------------------------------------------------------------
// CClientEngine::IsVisitorNetwork()
// ----------------------------------------------------------------------------
TBool CClientEngine::IsVisitorNetwork(const TMobileRoamingStatus& aRegNetworkStatus) const
    {
    LOG1("CClientEngine::IsVisitorNetwork. reg network status - %d",
			(TInt) aRegNetworkStatus);
        
    return (aRegNetworkStatus == EMobileNationalRoaming ||
        aRegNetworkStatus== EMobileInternationalRoaming);
    
    }

// ----------------------------------------------------------------------------
// CClientEngine::IsWlanOnly()
// ----------------------------------------------------------------------------
TBool CClientEngine::IsWlanOnly(const TMobileRoamingStatus& aRoamingStatus,
                                const TCmGenConnSettings& aGenConnSettings) const
    {
    LOG1("CClientEngine::IsVisitorNetwork. reg network status - %d",(TInt) aRoamingStatus);
    TBool wlanOnlyFlag = EFalse;
    switch(aRoamingStatus)
        {
        case EMobileRegHomeNetwork:
            LOG("Home network");
            wlanOnlyFlag = (aGenConnSettings.iCellularDataUsageHome == ECmCellularDataUsageDisabled);
            break;
        case EMobileNationalRoaming:
        case EMobileInternationalRoaming:
            LOG("Visitor network");
            wlanOnlyFlag = (aGenConnSettings.iCellularDataUsageVisitor == ECmCellularDataUsageDisabled);
            break;
        default:
            break;
        } // end of switch
    LOG1("Wlan only flag - %d", wlanOnlyFlag ? 1 : 0);
    return wlanOnlyFlag;
    }


// ----------------------------------------------------------------------------
// CClientEngine::UeRegNetworkStatus()
// ----------------------------------------------------------------------------
TMobileRoamingStatus CClientEngine::UeRegNetworkStatus()
    {
    LOG("CClientEngine::UeRegNetworkStatus() ,begin");
    TMobileRoamingStatus roamingStatus = EMobileNotRegistered;
    if(iObserver.IsRegisteredAtHomeNetwork())
        {
        // home network.
        roamingStatus = EMobileRegHomeNetwork;
        LOG("UE registered in home network");
        }
    else
        {
        // roaming network
        TBool homeNwInfoAvailableFlag = EFalse;
        const RMobilePhone::TMobilePhoneNetworkInfoV1& homeNwInfo = 
            iObserver.GetHomeNetworkInfo(homeNwInfoAvailableFlag);
        if(homeNwInfoAvailableFlag)
            {
            RMobilePhone::TMobilePhoneNetworkCountryCode countryCode = 
                        iObserver.GetCurrentRegisterNw().iCountryCode;
            if(countryCode.Compare(homeNwInfo.iCountryCode) == 0)
                {
                // national roaming..
                LOG("UE is in nation roaming");
                roamingStatus = EMobileNationalRoaming;
                }
            else
                {
                // international roaming.
                LOG("UE is in international roaming");
                roamingStatus = EMobileInternationalRoaming;
                }
            }                
        }
    if(roamingStatus == EMobileNotRegistered)
        {
        LOG("UE is not registered with the network. Offline mode.");
        }
	LOG("CClientEngine::UeRegNetworkStatus ,end");
    return roamingStatus;
    }

// ----------------------------------------------------------------------------
// CClientEngine::IsDataConnectionAskAlwaysL()
// ----------------------------------------------------------------------------
TBool CClientEngine::IsDataConnectionAskAlwaysL() 
    {
    LOG("CClientEngine::IsDataConnectionAskAlwaysL ,begin");
    TMobileRoamingStatus roamingStatus = UeRegNetworkStatus();
        
	TCmGenConnSettings genConnSettings;
    TBool retVal = EFalse;
	iCmManager.ReadGenConnSettingsL(genConnSettings);

    LOG1("wlan usage - %d", genConnSettings.iUsageOfWlan);
    LOG1("Home usage - %d", genConnSettings.iCellularDataUsageHome);
    LOG1("Visitor usage - %d", genConnSettings.iCellularDataUsageVisitor);
    
	if((IsWlanOnly(roamingStatus, genConnSettings) && genConnSettings.iUsageOfWlan == ECmUsageOfWlanManual) // wlan
		|| (roamingStatus == EMobileRegHomeNetwork &&  // home
        		genConnSettings.iCellularDataUsageHome == ECmCellularDataUsageConfirm)
		|| (IsVisitorNetwork(roamingStatus) &&  // roaming
    		 genConnSettings.iCellularDataUsageVisitor == ECmCellularDataUsageConfirm)
		)
		{
		retVal = ETrue;
		}
	LOG("CClientEngine::IsDataConnectionAskAlwaysL ,end");
	return retVal;
	}

// ----------------------------------------------------------------------------
// CClientEngine::SetupConnectionL()
// ----------------------------------------------------------------------------
void CClientEngine::SetupConnectionL( const TConnectionOption aOption )
    {
	LOG("CClientEngine::SetupConnectionL ,begin");
	if ( aOption == ESilent && IsDataConnectionAskAlwaysL())
		{
		LOG("Silent mode. connection setup is asked always.");
        if ( iConnectionSetupDone )
            {
            LOG("Already connected. Close the connection\n");
            CloseConnection();
            }
		User::Leave(KErrNotSupported);
		}
    if ( iConnectionSetupDone )
        {
        // Connection setup is done
        LOG("Already connected.\n");
        User::Leave(KErrAlreadyExists);
        }
 
	
    LOG1("SetupConnectionL: connection option: %d\n", aOption );
       
    // Open HTTP Session
    iSession.OpenL();
    User::LeaveIfError(iSocketServ.Connect());
    User::LeaveIfError(iConnection.Open(iSocketServ));
    
    if ( aOption == ESilent )
        {
        // Create overrides
        TConnPrefList prefList;
        TExtendedConnPref prefs;
        prefs.SetSnapPurpose( CMManager::ESnapPurposeInternet );
        prefs.SetNoteBehaviour( TExtendedConnPref::ENoteBehaviourConnSilent );
        prefList.AppendL( &prefs );
        
        iConnection.Start(prefList, iStatus);
        }
    else
        {
        iConnection.Start( iStatus );
        }
   
    
    SetActive();
	LOG("CClientEngine::SetupConnectionL ,end");
    }

// ----------------------------------------------------------------------------
// CClientEngine::SetHeaderL()
// ----------------------------------------------------------------------------
void CClientEngine::SetHeaderL( RHTTPHeaders aHeaders, TInt aHdrField, const TDesC8& aHdrValue )
    {
    LOG("CClientEngine::SetHeaderL ,begin");
    RStringF valStr = iSession.StringPool().OpenFStringL( aHdrValue );
    CleanupClosePushL( valStr );
    THTTPHdrVal val(valStr);
    aHeaders.SetFieldL( iSession.StringPool().StringF( aHdrField, RHTTPSession::GetTable()), val);
    CleanupStack::PopAndDestroy();  // valStr
    LOG("CClientEngine::SetHeaderL ,end");
    }

// ----------------------------------------------------------------------------
// CClientEngine::IssueHTTPGetL()
// ----------------------------------------------------------------------------
void CClientEngine::IssueHTTPGetL( const TDesC8& aUri, const TConnectionOption aOption )
    {
    LOG("CClientEngine::IssueHTTPGetL ,begin");
    if ( IsActive() )
        {
        // If there is some request in pending state
        // return with out further processing
        // Should we leave here !?
        LOG("Client engine is already active");
        return;
        }
    
    delete iUri;
    iUri = NULL;

    iUri = aUri.AllocL();

    // Create HTTP connection
    TRAPD( err, SetupConnectionL( aOption ) );
    //If the Err is KErrNone, It will lead to RunL and
    //hence jump to the DoHTTPGetL() from there.
    
    if( err == KErrAlreadyExists )
        {
        DoHTTPGetL();
        }
    else if( err != KErrNone )
        {
        LOG("Connection failure. Leaving.");
        iObserver.ClientEvent( EHttpConnectionFailure );
        User::Leave(err);
        }
    iEngineState = EGet;
 	LOG("CClientEngine::IssueHTTPGetL ,end");
    }

// ----------------------------------------------------------------------------
// CClientEngine::DoHTTPGetL()
// ----------------------------------------------------------------------------
void CClientEngine::DoHTTPGetL()
    {
    LOG("CClientEngine::DoHTTPGetL ,begin");
    // Parse string to URI (as defined in RFC2396)
    TUriParser8 uri;
    uri.Parse( *iUri );
    
    // Get request method string for HTTP GET
    RStringF method = iSession.StringPool().StringF( HTTP::EGET,RHTTPSession::GetTable() );
    
    // Open transaction with previous method and parsed uri. This class will
    // receive transaction events in MHFRunL and MHFRunError.
    iTransaction = iSession.OpenTransactionL( uri, *this, method );
    iTransactionOpen = ETrue;
    
    // Set headers for request; user agent and accepted content type
    RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection();
    SetHeaderL( hdr, HTTP::EUserAgent, KUserAgent );
    SetHeaderL( hdr, HTTP::EAccept, KAccept );
    
    // Submit the transaction. After this the framework will give transaction
    // events via MHFRunL and MHFRunError.
    iTransaction.SubmitL();
    
    iObserver.ClientEvent( EHttpConnecting );
	LOG("CClientEngine::DoHTTPGetL ,end");
}

// ----------------------------------------------------------------------------
// CClientEngine::CancelTransaction()
// ----------------------------------------------------------------------------
void CClientEngine::CancelTransaction()
    {
    LOG("CClientEngine::CancelTransaction ,begin");
    iEngineState = EIdle;
    delete iUri; 
    iUri = NULL;
    
    // Close() also cancels transaction (Cancel() can also be used but
    // resources allocated by transaction must be still freed with Close())
    if( iTransactionOpen )
        {
        iTransaction.Close();
        iTransactionOpen = EFalse;

        iObserver.ClientEvent( EHttpTxCancelled );
        }
	LOG("CClientEngine::CancelTransaction ,end");
    }

// ----------------------------------------------------------------------------
// CClientEngine::MHFRunL()
// ----------------------------------------------------------------------------
void CClientEngine::MHFRunL( RHTTPTransaction aTransaction, const THTTPEvent& aEvent )
    {
    LOG("CClientEngine::MHFRunL ,begin");
    switch ( aEvent.iStatus )
        {
        case THTTPEvent::EGotResponseHeaders:
            {
            // HTTP response headers have been received. Use
            // aTransaction.Response() to get the response. However, it's not
            // necessary to do anything with the response when this event occurs.
            iObserver.ClientEvent( EHttpHdrReceived );
            break;
            }
        case THTTPEvent::EGotResponseBodyData:
            {
            // Part (or all) of response's body data received. Use
            // aTransaction.Response().Body()->GetNextDataPart() to get the actual
            // body data.
        
            // Get the body data supplier
            MHTTPDataSupplier* body = aTransaction.Response().Body();
            TPtrC8 dataChunk;
        
            // GetNextDataPart() returns ETrue, if the received part is the last
            // one.
            TBool isLast = body->GetNextDataPart(dataChunk);
            iObserver.ClientBodyReceived(dataChunk);
        
            iObserver.ClientEvent( EHttpBytesReceieved );

            // NOTE: isLast may not be ETrue even if last data part received.
            // (e.g. multipart response without content length field)
            // Use EResponseComplete to reliably determine when body is completely
            // received.
            if( isLast )
                {
                iObserver.ClientEvent( EHttpBodyReceieved );
                }
            // Always remember to release the body data.
            body->ReleaseData();
            break;
            }
        case THTTPEvent::EResponseComplete:
            {
            // Indicates that header & body of response is completely received.
            // No further action here needed.

            iObserver.ClientEvent( EHttpTxCompleted );
            break;
            }
        case THTTPEvent::ESucceeded:
            {
            // Indicates that transaction succeeded.
            iObserver.ClientEvent( EHttpTxSuccess );
            // Transaction can be closed now. It's not needed anymore.
            aTransaction.Close();
            iTransactionOpen = EFalse;
            break;
            }
        case THTTPEvent::EFailed:
            {
            // Transaction completed with failure.
            iObserver.ClientEvent( EHttpTxFailed );
            aTransaction.Close();
            iTransactionOpen = EFalse;
            break;
            }
        default:
            // There are more events in THTTPEvent, but they are not usually
            // needed. However, event status smaller than zero should be handled
            // correctly since it's error.
            {
            if ( aEvent.iStatus < 0 )
                {
                iObserver.ClientEvent( EHttpConnectionFailure );
                // Close the transaction on errors
                aTransaction.Close();
                iTransactionOpen = EFalse;
                }
                break;
            }
        }
	LOG("CClientEngine::MHFRunL ,end");
    }

// ----------------------------------------------------------------------------
// CClientEngine::MHFRunError()
// ----------------------------------------------------------------------------
TInt CClientEngine::MHFRunError( TInt /*aError*/, RHTTPTransaction /*aTransaction*/, const THTTPEvent& /*aEvent*/ )
    {
    LOG("CClientEngine::MHFRunError ,begin");
    // Just notify about the error and return KErrNone.
    CloseConnection();
    iObserver.ClientEvent(EHttpMhfRunError);
    return KErrNone;
    }

// ----------------------------------------------------------------------------
// CClientEngine::PreferredCarrierAvailable()
// ----------------------------------------------------------------------------
void CClientEngine::PreferredCarrierAvailable( TAccessPointInfo /*aOldAPInfo*/,
                                               TAccessPointInfo /*aNewAPInfo*/,
                                               TBool /*aIsUpgrade*/,
                                               TBool aIsSeamless )
    {
    LOG("CClientEngine::PreferredCarrierAvailable ,begin");
    if( !aIsSeamless && iMobility)
        {
        iMobility->MigrateToPreferredCarrier();
        }
	LOG("CClientEngine::PreferredCarrierAvailable ,end");
    }

// ----------------------------------------------------------------------------
// CClientEngine::NewCarrierActive()
// ----------------------------------------------------------------------------
void CClientEngine::NewCarrierActive( TAccessPointInfo /*aNewAPInfo*/,
                                      TBool aIsSeamless )
    {
    LOG("CClientEngine::NewCarrierActive ,begin");
    if( !aIsSeamless && iMobility)
        {
        iMobility->NewCarrierAccepted();
        }
	LOG("CClientEngine::NewCarrierActive ,end");
    }

// ----------------------------------------------------------------------------
// CClientEngine::Error()
// ----------------------------------------------------------------------------
void CClientEngine::Error(TInt /*aError*/)
    {
    LOG("CClientEngine::Error");
    }

// ----------------------------------------------------------------------------
// CClientEngine::DoCancel()
// ----------------------------------------------------------------------------
void CClientEngine::DoCancel()
    {
    LOG("CClientEngine::DoCancel");
    iConnection.Stop();
    }

// ----------------------------------------------------------------------------
// CClientEngine::DoCancel()
// ----------------------------------------------------------------------------
TInt  CClientEngine::RunError(TInt /*aError*/)
    {
    LOG("CClientEngine::RunError");
    // Just notify about the error and return KErrNone.
    CloseConnection();
    iObserver.ClientEvent( EHttpTxFailed );
    return KErrNone;
    }
// ----------------------------------------------------------------------------
// CClientEngine::RunL()
// ----------------------------------------------------------------------------
void CClientEngine::RunL()
    {
    LOG1("CClientEngine::RunL: error is: %d\n", iStatus.Int() );
    TInt statusCode = iStatus.Int();
    if ( statusCode == KErrNone )
        {
        // Connection done ok
        iConnectionSetupDone = ETrue;
        
        RStringPool strPool = iSession.StringPool();

        // Remove first session properties just in case.
        RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
        
        // Clear RConnection and Socket Server instances
        connInfo.RemoveProperty(strPool.StringF(HTTP::EHttpSocketServ,RHTTPSession::GetTable()));
        connInfo.RemoveProperty(strPool.StringF(HTTP::EHttpSocketConnection,RHTTPSession::GetTable()));
        
        // Clear the proxy settings
        connInfo.RemoveProperty(strPool.StringF(HTTP::EProxyUsage,RHTTPSession::GetTable()));
        connInfo.RemoveProperty(strPool.StringF(HTTP::EProxyAddress,RHTTPSession::GetTable()));
        
        // RConnection and Socket Server
        connInfo.SetPropertyL ( strPool.StringF(HTTP::EHttpSocketServ, 
                                        RHTTPSession::GetTable()), 
                                THTTPHdrVal (iSocketServ.Handle()) );
        
        TInt connPtr1 = REINTERPRET_CAST(TInt, &iConnection);
        connInfo.SetPropertyL ( strPool.StringF(HTTP::EHttpSocketConnection, 
                                RHTTPSession::GetTable() ), THTTPHdrVal (connPtr1) );    

        // Register for mobility API
		if(iMobility)
			{
	        delete iMobility;
			iMobility = NULL ;
			}
        iMobility = CActiveCommsMobilityApiExt::NewL( iConnection, *this );
        // Start selected HTTP action
        switch( iEngineState )
            {
            case EIdle:
                {
                //
                CancelTransaction();
                break;
                }
            case EGet:
               {
               DoHTTPGetL();
               break;
               }
            };
        }
    else
        {
        //handle error
        if ( statusCode == KErrPermissionDenied )
            {
            iObserver.ClientEvent( EHttpAuthFailed );
            }
        else
            {
            //Throw some general Transaction falure error!
            iObserver.ClientEvent( EHttpTxFailed );
            }
        CloseConnection();
        }
	LOG("CClientEngine::RunL ,end");
    }

// ----------------------------------------------------------------------------
// CClientEngine::SilentConnectionAllowed()
// ----------------------------------------------------------------------------
TBool CClientEngine::SilentConnectionAllowed()
    {
    LOG("CClientEngine::SilentConnectionAllowed ,begin");
    TBool retVal = EFalse;
	TRAPD(err, retVal = IsDataConnectionAskAlwaysL());
	if(err == KErrNone)
		{
		// data connection is always ask... Silent connection is not allowed
		retVal = !retVal;
		}
	LOG1("CClientEngine::SilentConnectionAllowed ,end. Ret - %d", retVal);
    return retVal;
    }

// End of file