/*
* Copyright (c) 2002 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:  SyncML HTTP client
*
*/

#include <CoreApplicationUIsSDKCRKeys.h>
#include <centralrepository.h>
#include <featmgr.h>   // FeatureManager
#include <cmdefconnvalues.h>
#include <cmmanager.h>
#include <cmmanagerkeys.h>
#include <rconnmon.h>
#include <nsmldmconst.h>
#include <nsmlconstants.h>
#include <etelpckt.h>
#include <etel.h> //for telephone mode
#include <etelmm.h> //for telephone mode
#include "nsmldialiap.h"
#include <nsmlconstants.h>
#include "nsmlerror.h"


//------------------------------------------------------------
// CNSmlDialUpAgent::CNSmlDialUpAgent() 
// constructor
//------------------------------------------------------------
CNSmlDialUpAgent::CNSmlDialUpAgent() 
	: CActive( EPriorityStandard ){}
//------------------------------------------------------------
// CNSmlDialUpAgent::~CNSmlDialUpAgent()
// desctructor
//------------------------------------------------------------
CNSmlDialUpAgent::~CNSmlDialUpAgent()
	{
	FeatureManager::UnInitializeLib();
	Cancel();
	// close handles for sure
	if( !iCancelCalled && iSocketConnection )
		{
		iConnection.SetOpt( KCOLProvider, KConnDisableTimers, EFalse );		
		iConnection.Close();
		iSocketServer.Close();
		}
	}
// --------------------------------------------------------------------
// CNSmlDialUpAgent::ConstructL()
// 2-phase
// --------------------------------------------------------------------
void CNSmlDialUpAgent::ConstructL(TBool aDmJob)
    {
	DBG_FILE( _S8("CNSmlDialUpAgent::ConstructL") );
	CActiveScheduler::Add( this );
	iCancelCalled = EFalse;    
	iSocketConnection = EFalse;  
	iDmjob = aDmJob;
	FeatureManager::InitializeLibL();  
	}
//------------------------------------------------------------
// CNSmlDialUpAgent::DoCancel()
// DoCancel() from CActive
//------------------------------------------------------------
void CNSmlDialUpAgent::DoCancel() 
	{
	DBG_FILE( _S8("CNSmlDialUpAgent::DoCancel...") );
	iCancelCalled = ETrue;
	if(iSocketConnection)
	{
	iConnection.SetOpt( KCOLProvider, KConnDisableTimers, EFalse );
	iConnection.Close();
	iSocketServer.Close();
	iSocketConnection = EFalse;
	}
	}
//------------------------------------------------------------
// CNSmlDialUpAgent::RunL()
// Runl() from CActive
// called when asynchronous request completed
//------------------------------------------------------------
void CNSmlDialUpAgent::RunL() 
	{
	DBG_FILE_CODE( iStatus.Int(), _S8("CNSmlDialUpAgent::RunL with status") );
	
	/**
	   In 2G Calls , data and voice are not allowed in same channel
	   If the error code is KErrGprsServicesNotAllowed and if access point is 
	   not Always ask, every minute retry is made , max for 35 times
	**/
	TInt isAccessPointDefined = EFalse;
	if (static_cast<TInt32>(iIAPid) == -2)
	{
		RCmManager cmmgr;
		cmmgr.OpenL();
		TCmDefConnValue defConnValue;
		cmmgr.ReadDefConnL(defConnValue);
		cmmgr.Close();
		if(defConnValue.iType == ECmDefConnDestination)
		{
			isAccessPointDefined = ETrue;
		}
	}
	else
	{
		if(static_cast<TInt32>(iIAPid)!=-1)
		{
		isAccessPointDefined = ETrue;	
		}
	}
	if( iRetryCounter<KNSmlConNumberOfRetries && !iTimerReturn && 
		iStatus.Int()==KErrGprsServicesNotAllowed && 
		isAccessPointDefined)
	    {
	      DBG_FILE( _S8("CNSmlDialUpAgent::RunL() ,Timer is started"));
		    DBG_FILE_CODE(iRetryCounter, _S8("CNSmlDialUpAgent::RunL() for Iteration "));
		    
		    iTimerReturn=ETrue;
	    	iTimer.CreateLocal();
	      iTimer.After( iStatus, TTimeIntervalMicroSeconds32(KNSmlConRetryInterval));
	      iConnection.Close();
		  iSocketServer.Close();
		  iSocketConnection = EFalse;
	      SetActive();
	      return;
	    }
	 else if(iRetryCounter<KNSmlConNumberOfRetries && iTimerReturn)
	    {
	        DBG_FILE_CODE(iRetryCounter, _S8("CNSmlDialUpAgent::RunL() Retrying connection"));
	        Cancel();
	        iTimerReturn=EFalse;
	        iRetryCounter++;
	       	TRAPD( ret, StartDatacallL() );
	        if ( ret != KErrNone )
	            {
		            TRequestStatus* status = &iStatus;
				    		User::RequestComplete( status, ret );		
	            }
	        return;    
        }
    if ( iStatus.Int() != KErrNone && iIAPCnt < iIAPArray->Count() )
        {
        this->Cancel();        
        iIAPid = iIAPArray->At( iIAPCnt );
        DoSettingsL();

        iIAPCnt++;

        TRAPD( ret, StartDatacallL() );
        if ( ret != KErrNone )
            {
            TRequestStatus* status = &iStatus;
		    User::RequestComplete( status, ret );		
            }
        }
    else
        {
	    if ( iStatus.Int() == KErrCancel )
	    	{
	    	this->Cancel();
            iStatus = KErrCancel;
	    	}
	    else if ( iStatus.Int() != KErrNone )
	    	{
	    	this->Cancel();
            iStatus = TNSmlError::ESmlCommunicationError;
	    	}
	    if(iSocketConnection)
	    {
	    iConnection.SetOpt( KCOLProvider, KConnDisableTimers, ETrue );
	    }
	    TRequestStatus* status = iEngineStatus;
	    User::RequestComplete( status, iStatus.Int() );			
        }
	}
// ---------------------------------------------------------
// CNSmlDialUpAgent::ConnectL( TUint aIAPid, TRequestStatus &aStatus )
// Opens data call handle 
// This is asynchronous request 
// ---------------------------------------------------------
void CNSmlDialUpAgent::ConnectL( CArrayFixFlat<TUint32>* aIAPIdArray, TRequestStatus &aStatus )
	{
	//DBG_FILE_CODE( aIAPid, _S8("CNSmlDialUpAgent::ConnectL") );
	// aStatus set pending from HTTP
	iCancelCalled = EFalse;
	iEngineStatus = &aStatus;

    iIAPCnt = 0;
    iIAPArray = aIAPIdArray;


	TBool connected( EFalse );
	TRAPD( err, ( connected = IsConnectedL() ) );
	if( err != KErrNone )
		{
		TRequestStatus* status = &iStatus;
		User::RequestComplete( status, err );		
		}
	if( !connected )
		{
        iIAPid = iIAPArray->At( iIAPCnt );
        DoSettingsL();

        iIAPCnt++;

        TRAPD( ret, StartDatacallL() );
        if ( ret != KErrNone )
            {
            TRequestStatus* status = &iStatus;
		    User::RequestComplete( status, ret );		
            }
/*
			#ifdef __WINS__
	            if ( !IsConnectedL() )
		            {						
					if ( !IsConnectedL() )	// Double check
						{
						this->Cancel();
						iIAPCnt++;
						}
					else
						{
						callStarted = ETrue;
						}
	                }
		        else
			        {
				    callStarted = ETrue;
					}
			#else
	            if ( !IsConnectedL() )
	                {
		            this->Cancel();
			        iIAPCnt++;
				    }
	            else
		            {
			        callStarted = ETrue;
				    }
			#endif
*/

		}
	else
		{
		TRAPD( error, AttachToConnectionL() );
		TRequestStatus* status = &iStatus;
		User::RequestComplete( status, error );		
		}  
	}
// ---------------------------------------------------------
// CNSmlDialUpAgent::StartDatacallL()
// Opens data call handle 
// This is asynchronous request 
// ---------------------------------------------------------
void CNSmlDialUpAgent::StartDatacallL()
    {
    DBG_FILE( _S8("CNSmlDialUpAgent::StartDatacallL") );
    SetActive();
    User::LeaveIfError( iSocketServer.Connect() );		
    User::LeaveIfError( iConnection.Open( iSocketServer ) );
    iSocketConnection = ETrue;
    iConnection.Start( iPrefList, iStatus );
    }
	
// ---------------------------------------------------------
// CNSmlDialUpAgent::AttachToConnectionL()
// Attach to connection allready active 
// 
// ---------------------------------------------------------
void CNSmlDialUpAgent::AttachToConnectionL()
	{
	DBG_FILE( _S8("CNSmlDialUpAgent::AttachToConnectionL") );
	iStatus = KRequestPending;
	SetActive();
	TConnectionInfo connectionInfo;
	TConnectionInfoBuf connInfo( connectionInfo );
	
	User::LeaveIfError( iSocketServer.Connect() );
	User::LeaveIfError( iConnection.Open( iSocketServer ) );
	
	TUint count( 0 );
	User::LeaveIfError( iConnection.EnumerateConnections ( count ) );
	DBG_FILE_CODE( count, _S8("Number of connections ") );
	
	if( count == 0 )
		{
		iConnection.Close();
		iSocketServer.Close();
		User::Leave( KErrNotFound );
		}
	else{
		for( TUint i=1; i<=count; ++i )
			{
			User::LeaveIfError( iConnection.GetConnectionInfo( i, connInfo ) );
			DBG_FILE_CODE( connInfo().iIapId, _S8("Comparing IDs ") );			
			if( connInfo().iIapId == iIAPid )
				{
				DBG_FILE_CODE( iIAPid, _S8("Attaching to existing connection, IDs match") );
				User::LeaveIfError( iConnection.Attach( connInfo, RConnection::EAttachTypeNormal ) );				
				break;
				}
			}
		}
	}
// ---------------------------------------------------------
// CNSmlDialUpAgent::IsConnectedL()
// Checks if data call is up or connecting
// ---------------------------------------------------------
TBool CNSmlDialUpAgent::IsConnectedL() const
	{
	DBG_FILE( _S8("CNSmlDialUpAgent::IsConnected") );
	TInt err( KErrNone );
	TBool isConnected( EFalse );
	TConnectionInfo connectionInfo;
	TConnectionInfoBuf connInfo( connectionInfo );

	RSocketServ serv;
	CleanupClosePushL( serv );
	User::LeaveIfError( serv.Connect() );

	RConnection conn;
	CleanupClosePushL( conn );
	User::LeaveIfError( conn.Open( serv ) );

	TUint count( 0 );
	User::LeaveIfError( conn.EnumerateConnections ( count ) );
	DBG_FILE_CODE( count, _S8("Number of connections ") );
	
	if( count == 0 )
		{
		CleanupStack::PopAndDestroy( 2 ); // conn, serv
		return isConnected;
		}
	else{
		for( TUint i=1; i<=count; ++i )
			{
			err = conn.GetConnectionInfo( i, connInfo );
			if( err != KErrNone )
				{
				CleanupStack::PopAndDestroy( 2 ); // conn, serv
				User::Leave( err );				
				}	
			DBG_FILE_CODE( connInfo().iIapId, _S8("Comparing IDs ") );
			if( connInfo().iIapId == iIAPid )
				{
				DBG_FILE( _S8("Connection allready active") );
				isConnected = ETrue;
				break;
				}
		    }
		}
	CleanupStack::PopAndDestroy( 2 ); // conn, serv
	return isConnected;
	}
// ---------------------------------------------------------
// CNSmlDialUpAgent::DoSettingsL()
//  
//  
// ---------------------------------------------------------
void CNSmlDialUpAgent::DoSettingsL()
    {
    DBG_FILE( _S8("CNSmlDialUpAgent::DoSettingsL") );
    iOffline=IsInOfflineModeL();            
    iExtPrefs.SetForcedRoaming(EFalse);
    if(  ( static_cast<TInt32>(iIAPid) == -2 ) || 
            static_cast<TInt32>(iIAPid) == -1 ) // default connection
        {
        TBool Snap = EFalse;
        RCmManager cmmgr;
        cmmgr.OpenL();
        TCmDefConnValue defConnValue;
        cmmgr.ReadDefConnL(defConnValue);
        cmmgr.Close();
        if(defConnValue.iType == ECmDefConnDestination)
            {
            iExtPrefs.SetSnapId(defConnValue.iId);
            Snap = ETrue;
            }
        else if(defConnValue.iType == ECmDefConnConnectionMethod)
            {
            iExtPrefs.SetIapId(defConnValue.iId);   
            }
            iExtPrefs.SetConnSelectionDialog(EFalse);
        if(iDmjob)
            {            
            TInt val = KErrNotFound;
            TInt r2=RProperty::Get(KPSUidNSmlSOSServerKey,KNSmlDMSilentJob,val);
			DBG_FILE_CODE( r2, _S8("CNSmlDialUpAgent::DoSettingsL dc KNSmlDMSilentJob set error code") );
            if(val == ESilent) //silent session
                {
                //Check the cenrep key
                TInt currentmode = KErrNone;
                CRepository* rep = CRepository::NewLC( KCRUidCmManager );
                rep->Get(KCurrentCellularDataUsage, currentmode );
                CleanupStack::PopAndDestroy(); //rep
                //if "Always ask", check the roam or home
                // if snap dont allow silent connections at all in"always ask"
                if(Snap)//Check also for roaming n/w IAP as d.c case
                    {
                    //Check the general settings                
                    if(ECmCellularDataUsageConfirm ==  currentmode)
                        {
                        //As silent session fails in roam or home with snap, then dont go for silent sessions .
                        iExtPrefs.SetNoteBehaviour(TExtendedConnPref::ENoteBehaviourDefault  );
                        }
                    else
                        {
                        iExtPrefs.SetNoteBehaviour(TExtendedConnPref::ENoteBehaviourConnSilent );
                        }
                    }
                else //IAP as d.c
                    {

                    //dont set any preference, as this leads to fail  
                    //else //home n/w or roam n/w with automatic or WLAN only
                    TBool roaming = EFalse;
                    IsRoamingL(roaming);
                    if(ECmCellularDataUsageConfirm ==  currentmode && roaming)
                        {
                        //No silent connection preference, as this leads to failure of connection
                        iExtPrefs.SetNoteBehaviour(TExtendedConnPref::ENoteBehaviourDefault  );
                        }
                    else
                        iExtPrefs.SetNoteBehaviour(TExtendedConnPref::ENoteBehaviourConnSilent );
                    }
                RProperty::Set(KPSUidNSmlSOSServerKey,KNSmlDMSilentJob,KErrNone);
                }
            }
        }
    else
        {
        iExtPrefs.SetIapId(iIAPid);
        iExtPrefs.SetConnSelectionDialog(EFalse);
        if(iDmjob)
            {
            TInt val = KErrNotFound;
            TInt r2=RProperty::Get(KPSUidNSmlSOSServerKey,KNSmlDMSilentJob,val);
			DBG_FILE_CODE( r2, _S8("CNSmlDialUpAgent::DoSettingsL IAP KNSmlDMSilentJob set error code") );
            if(val == ESilent) //silent session
               {
                //Check the cenrep key
                TInt currentmode = KErrNone;
                CRepository* rep = CRepository::NewLC( KCRUidCmManager );
                rep->Get(KCurrentCellularDataUsage, currentmode );
                CleanupStack::PopAndDestroy(); //rep          
                TBool roaming = EFalse;
                IsRoamingL(roaming);  
                if(ECmCellularDataUsageConfirm ==  currentmode && roaming )
                    {
                    //As silent session fails in roam or home with snap, then dont go for silent sessions .
                    iExtPrefs.SetNoteBehaviour(TExtendedConnPref::ENoteBehaviourDefault  );
                    }
                else
                    {
                    iExtPrefs.SetNoteBehaviour(TExtendedConnPref::ENoteBehaviourConnSilent );
                    }
               }
            }
        RProperty::Set(KPSUidNSmlSOSServerKey,KNSmlDMSilentJob,KErrNone);
        }
    iPrefList.AppendL(&iExtPrefs);

    }
//----------------------------------------------------------
//CNsmlDialUpAgent::IsOfflineModeL()
//------------------------------------------------------------	
TBool CNSmlDialUpAgent::IsInOfflineModeL()
    {
    TInt operationsAllowed( ECoreAppUIsNetworkConnectionAllowed );
	CRepository* rep = CRepository::NewLC( KCRUidCoreApplicationUIs );
	rep->Get(KCoreAppUIsNetworkConnectionAllowed, operationsAllowed );
	CleanupStack::PopAndDestroy(); //rep
	
    return ( operationsAllowed == ECoreAppUIsNetworkConnectionNotAllowed ) ? ETrue : EFalse;
    }

//------------------------------------------------------------
// CNSmlDialUpAgent::IsRoamingL()
//  Returns roaming network or not
//------------------------------------------------------------	
void CNSmlDialUpAgent::IsRoamingL( TBool& aRoaming)
    {
     	RTelServer telServer;
	User::LeaveIfError( telServer.Connect());
	
	RTelServer::TPhoneInfo teleinfo;
	User::LeaveIfError( telServer.GetPhoneInfo( 0, teleinfo ) );
	
	RMobilePhone phone;
	User::LeaveIfError( phone.Open( telServer, teleinfo.iName ) );
	
	User::LeaveIfError(phone.Initialise());	
	
	RMobilePhone::TMobilePhoneNetworkMode mode;        	        	
	TInt err = phone.GetCurrentMode( mode );
	phone.Close();
	telServer.Close();
	TInt Bearer = EBearerIdGSM ;
	if( KErrNone == err )
		{
		switch(mode)
		{
		case RMobilePhone::ENetworkModeGsm:		
			{
			Bearer = EBearerIdGSM; 			
			break;		
			}
		case RMobilePhone::ENetworkModeWcdma:
			{                		     		
			Bearer = EBearerIdWCDMA  ;			
			}	
		default: 
			{       			
			break;
			}        				
		}
	}	
    RConnectionMonitor monitor;
    TRequestStatus status;
    // open RConnectionMonitor object
    monitor.ConnectL();
    CleanupClosePushL( monitor );
    TInt netwStatus(0);
    monitor.GetIntAttribute( Bearer, 
            0, 
            KNetworkRegistration,
            netwStatus, 
            status );
    User::WaitForRequest( status );
    CleanupStack::PopAndDestroy(); // Destroying monitor
    if ( status.Int() == KErrNone && netwStatus == ENetworkRegistrationRoaming )
        {
        aRoaming = ETrue;
        }
    else //home n/w or some other state in n/w
        {
        aRoaming = EFalse;
        }
}
