// Copyright (c) 2008-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:
//



//  INCLUDE FILES
#include "cmmconferencecallgsmwcdmaext.h"
#include "cmmphonetsy.h"
#include "cmmconferencecalltsy.h"
#include "cmmvoicecalltsy.h"
#include "cmmcalllist.h"
#include "cmmcallgsmwcdmaext.h"
#include <ctsy/pluginapi/cmmdatapackage.h>
#include "cmmmessagemanagerbase.h"
#include <etelmmerr.h> // etel error codes

// ======== MEMBER FUNCTIONS ========

CMmConferenceCallGsmWcdmaExt::CMmConferenceCallGsmWcdmaExt()
    {
    }

CMmConferenceCallGsmWcdmaExt::~CMmConferenceCallGsmWcdmaExt()
    {
    iMmConferenceCallTsy = NULL;
    }

CMmConferenceCallGsmWcdmaExt* CMmConferenceCallGsmWcdmaExt::NewL(
    CMmConferenceCallTsy* aMmConferenceCallTsy )
    {
    CMmConferenceCallGsmWcdmaExt* const conferenceCallGsmWcdmaExt = 
        new ( ELeave ) CMmConferenceCallGsmWcdmaExt();
    
    CleanupStack::PushL( conferenceCallGsmWcdmaExt );
    conferenceCallGsmWcdmaExt->iMmConferenceCallTsy = aMmConferenceCallTsy;
    conferenceCallGsmWcdmaExt->ConstructL();
    CleanupStack::Pop();

    return conferenceCallGsmWcdmaExt;
    }

void CMmConferenceCallGsmWcdmaExt::ConstructL()
    {
    ResetAttributes();
    }

// ======== LOCAL FUNCTIONS ========

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::CreateConferenceL
// This method allows clients to create the initial conference call.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmConferenceCallGsmWcdmaExt::CreateConferenceL(
    RMobileConferenceCall::TMobileConferenceStatus aStatus )
    {
    TInt ret = KErrNotReady;

    //This method allows clients to create the inital 3-way conference call. 
    //The phone must be in a state where there are two single voice calls, 
    //one on hold and the other connected or alerting the remote, called party. 
    //The TSY will reflect the conference creation capability by setting 
    //the KCapsJoin flags of the individual calls and the KCapsCreate flag 
    //of the conference call sub-session.
    //
    //In GSM mode, this method will complete when the TSY has received 
    //confirmation from the network that the conference call service has been 
    //successfully invoked.

    //This check is required because Add call uses same DOS operation to 
    //as this one. Therefore we don't want to continue if status is not
    //Idle.     
    if ( RMobileConferenceCall::EConferenceIdle == aStatus )
        {
        //We have to get 2 active status indications before the conference 
        //has really gone to active state.
        iCreateConferenceCounter = 2;

#ifndef USING_CTSY_DISPATCHER
        //send request to DOS
		// no packaged parameters for DOS call
		ret = iMmConferenceCallTsy->Phone()->MessageManager()->
            HandleRequestL( EMobileConferenceCallCreateConference );
#else
		// Pass down the call IDs of the active and held calls to be
		// joined in the conference.
		TInt heldCallId = iMmConferenceCallTsy->HeldCall()->CallId();
		TInt connectedCallId = iMmConferenceCallTsy->ConnectedCall()->CallId();
		CCallDataPackage package;
		package.SetCallIdAndMode(heldCallId, iMmConferenceCallTsy->HeldCall()->CallMode());
		package.PackData(&connectedCallId);
		ret = iMmConferenceCallTsy->Phone()->MessageManager()->
			HandleRequestL( EMobileConferenceCallCreateConference, &package);
#endif   // USING_CTSY_DISPATCHER
        }

    //return request result
    return ret;

    }

#ifndef USING_CTSY_DISPATCHER

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::AddCallL
// Addition of a new call to an existing conference call. If 
// call object is not found by the name given as input parameter KErrArgument
// will be returned.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmConferenceCallGsmWcdmaExt::AddCallL(
    const TName* aCallName,
    RMobileConferenceCall::TMobileConferenceStatus aStatus,
    CMmCallList* aCallList )
    {
    TInt ret = KErrArgument;

    // Get the call object that should be added to the conference call
    CMmCallTsy* mmCall = aCallList->GetMmCallByName( aCallName );
    if ( mmCall ) 
        {
        // Fetch the active call extension
        CMmCallGsmWcdmaExt* mmCallGsmWcdmaExt = static_cast<CMmCallGsmWcdmaExt*>( mmCall->ActiveCallExtension() );
        // Get the mobile call capabilities
        RMobileCall::TMobileCallCapsV1 mobileCallCaps;
        mmCallGsmWcdmaExt->GetMobileCallCapsV1(mobileCallCaps);
        // Only calls whose call control capabilities include KCapsJoin can be added to a conference call.
        if( !( RMobileCall::KCapsJoin & mobileCallCaps.iCallControlCaps ))
        	{ // Do not add the call to the conference since the call doesn't have KCapsJoin capability.
        	if(KMaxCallsInConference <= iMmConferenceCallTsy->NumberOfCallsInConference())
        		return KErrMMEtelMaxReached;
        	return ret;
        	} 

        RMobileCall::TMobileCallStatus callStatus = 
            mmCall->MobileCallStatus();
        //check that this call is not in hold or connected  state and 
        //conference call is not idle (=no reason to try this)
        if ( ( ( callStatus == RMobileCall::EStatusHold ) ||
                ( callStatus == RMobileCall::EStatusConnected ) )
            && ( RMobileConferenceCall::EConferenceIdle != aStatus ) )
            {
            // send request to DOS
            // only packed parameter for DOS call: Id of the call to be added
            CCallDataPackage callDataPackage;
            callDataPackage.SetCallIdAndMode( mmCall->CallId(), 
                RMobilePhone::EServiceUnspecified ); // service type not needed
            ret = iMmConferenceCallTsy->Phone()->MessageManager()->
                    HandleRequestL( EMobileConferenceCallAddCall,
                    &callDataPackage );
            }
        }

    return ret;
    }
#endif //USING_CTSY_DISPATCHER

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::SwapL
// This method can be used to swap the ongoing conference call
// between active and held status. 
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmConferenceCallGsmWcdmaExt::SwapL(
	RMobileConferenceCall::TMobileConferenceStatus aStatus,
    CMmCallList* aCallList )
    {
TFLOGSTRING("TSY: CMmConferenceCallGsmWcdmaExt::SwapL");
	TInt ret = KErrArgument;

	// conference must be active or held
    if ( aStatus == RMobileConferenceCall::EConferenceIdle )
        {
        ret = KErrNotReady;
        }
    else
        {
        // Init counter
        iNumberOfCallsToBeSwapped = 0;
        CMmCallTsy* mmCall = NULL;
        CMmCallList* callList = iMmConferenceCallTsy->Phone()->CallList();

        // Check from call list the number of calls to be swapped
        for ( TInt i = 0; i < callList->GetNumberOfObjects(); i++ )
            {
            mmCall = callList->GetMmCallByIndex( i );

            if ( mmCall->IsPartOfConference() 
                && ( mmCall->MobileCallStatus() == RMobileCall::EStatusHold 
                || mmCall->MobileCallStatus() == RMobileCall::EStatusConnected ) )
                {
                // Call found, increase the counter.
                iNumberOfCallsToBeSwapped++;
                }
            }
TFLOGSTRING2("TSY: CMmConferenceCallGsmWcdmaExt::SwapL - Number of calls in conference: %d", iNumberOfCallsToBeSwapped);

        // Find active and held call objects:
        CMmCallTsy* mmActiveCall = 
            aCallList->GetMmCallByStatus( RMobileCall::EStatusConnected );
        CMmCallTsy* mmHeldCall = 
            aCallList->GetMmCallByStatus( RMobileCall::EStatusHold ); 

        if ( RMobileConferenceCall::EConferenceActive == aStatus )
            {
            // conference is active
            // if held call is found, swap operation is required
            if ( mmHeldCall )
                {
#ifndef USING_CTSY_DISPATCHER
                // need to swap
                // no packed parameters for DOS call
                ret = iMmConferenceCallTsy->Phone()->MessageManager()->
                    HandleRequestL( EMobileConferenceCallSwap );
#else
                if (mmActiveCall && mmCall)
                	{
	                CCallDataPackage callDataPackage;
	                callDataPackage.SetCallIdAndMode( mmCall->CallId(),
	                		RMobilePhone::EServiceUnspecified ); // service type not needed
	                TInt heldCallId = mmHeldCall->CallId();
	                TInt connectedCallId = mmActiveCall->CallId();
	                callDataPackage.PackData(&heldCallId, &connectedCallId);
	                ret = iMmConferenceCallTsy->Phone()->MessageManager()->
	                		HandleRequestL(EMobileConferenceCallSwap, &callDataPackage);
                	}
                else
                	{
                	ret = KErrNotReady; // Shouldn't happen
                	}
#endif // USING_CTSY_DISPATCHER
                }
            // if held call is not found, there should be an active call
	        // and hold operation is required
            else if ( mmActiveCall )
                {
                // need to hold the active (conference) call

                // create package; set call id and call mode
                CCallDataPackage package;
                package.SetCallIdAndMode( mmActiveCall->CallId(),
                    mmActiveCall->CallMode() );

                // send to DOS
                ret = iMmConferenceCallTsy->Phone()->MessageManager()->
                    HandleRequestL( EMobileCallHold, &package );
                }
            // we have neither an active nor a held call
            else
                {
                ret = KErrNotReady; // should never happen
                }
            }
        else if ( RMobileConferenceCall::EConferenceHold == aStatus )
            {
            // conference is held
            //if active call is found, swap operation is required
            if ( mmActiveCall )
                {
#ifndef USING_CTSY_DISPATCHER
                // need to swap
                // no packed parameters for DOS call
                ret = iMmConferenceCallTsy->Phone()->MessageManager()->
                    HandleRequestL( EMobileConferenceCallSwap );
#else
                if (mmHeldCall && mmCall)
                	{
	                CCallDataPackage callDataPackage;
	                callDataPackage.SetCallIdAndMode( mmCall->CallId(),
	                		RMobilePhone::EServiceUnspecified ); // service type not needed
	                TInt heldCallId = mmHeldCall->CallId();
	                TInt connectedCallId = mmActiveCall->CallId();
	                callDataPackage.PackData(&heldCallId, &connectedCallId);
	                ret = iMmConferenceCallTsy->Phone()->MessageManager()->
	                		HandleRequestL(EMobileConferenceCallSwap, &callDataPackage);
                	}
                else
                	{
                	ret = KErrNotReady; // Shouldn't happen
                	}
#endif // USING_CTSY_DISPATCHER
                }
            // if active call is not found, there should be a held call
            // and resume operation is required
            else if ( mmHeldCall )
                {
                // need to retrieve (unhold) the held call

                // create package; set call id and call mode
                CCallDataPackage package;
                package.SetCallIdAndMode( mmHeldCall->CallId(),
                    mmHeldCall->CallMode() );

                // send to DOS
                ret = iMmConferenceCallTsy->Phone()->MessageManager()->
                    HandleRequestL( EMobileCallResume, &package );
                }
            // we have neither an active nor a held call
            else
                {
                ret = KErrNotReady; // should never happen
                }
            }
        }

    return ret;
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::CallStatusChanged
// After the status of a single call has changed, this method decides if
// the status of the conference call should be changed as well.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TBool CMmConferenceCallGsmWcdmaExt::CallStatusChanged(
    RMobileCall::TMobileCallStatus aNewStatus,
    TInt aCallId )
    {
TFLOGSTRING3("TSY: CMmConferenceCallGsmWcdmaExt::CallStatusChanged, aNewStatus:%d, aCallId:%d", aNewStatus, aCallId );

    TBool statusChanged( EFalse );

    //get current conference call status
    RMobileConferenceCall::TMobileConferenceStatus status 
            = iMmConferenceCallTsy->Status();

TFLOGSTRING2("TSY: CMmConferenceCallGsmWcdmaExt::CallStatusChanged, Current conf call iMmConferenceCallTsy->Status:%d ", status);
TFLOGSTRING2("TSY: CMmConferenceCallGsmWcdmaExt::CallStatusChanged, Current conference extension iNewStatus:%d ", iNewStatus);
    //get call list
    CMmCallList* callList = iMmConferenceCallTsy->Phone()->CallList();

    switch( aNewStatus )
        {
        //call has gone to idle state
        case RMobileCall::EStatusIdle:
            //If conference call is in active or held state 
            if ( ( RMobileConferenceCall::EConferenceActive == status ||
                   RMobileConferenceCall::EConferenceHold == status ) )           
                {
                //handle call releasing
                statusChanged = HandleCallRelease(
                    status, *callList, aNewStatus, aCallId );
                }
            break;
        //call has gone to held state
        case RMobileCall::EStatusHold:
            //if conference call is in active state
            if ( RMobileConferenceCall::EConferenceActive == status )
                {
                //check if swap request is pending
                if ( iMmConferenceCallTsy->ServiceRequested(
                        CMmConferenceCallTsy::EMultimodeConferenceCallSwap )
                     || iCurrentGhostOperation ==
                        RMobileConferenceCall::EConferenceSwapped )
                    {
                    //handle swapping
                    statusChanged = HandleSwap( status, *callList );
                    }
                //is GoOneToOne going on
                else if ( iGoOneToOneHandlingStarted )
                    {
                    statusChanged = HandleGoOneToOne( *callList, aCallId );
                    }
                //check that add call request is not pending
                else if ( !iMmConferenceCallTsy->ServiceRequested( 
                    CMmConferenceCallTsy::EMultimodeConferenceCallAddCall ) )
                    {
                    //Client has requested hold for a single call. If the call is part
                    //of the conference, all calls participating in the conference
                    //call will be held.
                    CMmCallTsy* call = callList->GetMmCallById(aCallId);
                    if(call != NULL && call->IsPartOfConference())
                    	{
                    	statusChanged = HandleSingleCallControl(status, aNewStatus);
                    	}
                    }
                }
            break;
        //call has gone to active state
        case RMobileCall::EStatusConnected:
            //check if CreateConference request is pending
            if ( ( iMmConferenceCallTsy->ServiceRequested(
                    CMmConferenceCallTsy::EMultimodeConferenceCallCreateConference )
                 || iCurrentGhostOperation == RMobileConferenceCall::EConferenceBuilt ) 
                 && RMobileConferenceCall::EConferenceIdle == status )
                {
                //handle create conference
                statusChanged = HandleCreateConference(
                    *callList, aCallId );
                }
            //check if AddCall request is pending
            else if ( ( iMmConferenceCallTsy->ServiceRequested(
                    CMmConferenceCallTsy::EMultimodeConferenceCallAddCall ) ||
                iCurrentGhostOperation ==  RMobileConferenceCall::EConferenceBuilt ||
                iCurrentGhostOperation ==  RMobileConferenceCall::EConferenceCallAdded ) &&
                ( RMobileConferenceCall::EConferenceActive == status ||
                RMobileConferenceCall::EConferenceHold == status ) )
                {
                //handle add call...
                statusChanged = HandleAddCall( status, *callList,
                    aNewStatus );
                }
            //check if swap request is pending
            else if ( iMmConferenceCallTsy->ServiceRequested(
                    CMmConferenceCallTsy::EMultimodeConferenceCallSwap ) ||
                iCurrentGhostOperation ==  RMobileConferenceCall::EConferenceSwapped )
                {
                //is conference status hold
                if ( RMobileConferenceCall::EConferenceHold == status )
                    {
                    //handle swap...
                    statusChanged = HandleSwap( status, *callList );
                    }
                }
            // call status might have changed because client has requested it
            // directly from a call object which is part of the conference
            // (not from the conference call object).
            else if ( RMobileConferenceCall::EConferenceHold == status )
                {
                CMmCallTsy* mmCall = callList->GetMmCallById( aCallId );
                if ( mmCall )
                    {
                    if ( mmCall->IsPartOfConference() )
                        {
                        // if this call is part of the conference, conference
                        // status is Hold and new call status is Connected, we
                        // have to get the whole conference into active state
                        statusChanged = HandleSingleCallControl(
                            status, aNewStatus );
                        }
                    }
                }
            break;
        case RMobileCall::EStatusUnknown:
        case RMobileCall::EStatusDialling:
        case RMobileCall::EStatusRinging:
        case RMobileCall::EStatusAnswering:
        case RMobileCall::EStatusConnecting:
        case RMobileCall::EStatusDisconnecting:
        case RMobileCall::EStatusDisconnectingWithInband:
        case RMobileCall::EStatusReconnectPending:
        case RMobileCall::EStatusWaitingAlternatingCallSwitch:
        case RMobileCall::EStatusTransferring:
        case RMobileCall::EStatusTransferAlerting:
        default:
            break;
        }

    if ( statusChanged )
        {
        // -1 indicates that there is no unhandled ghost operation anymore
        iCurrentGhostOperation = -1;
TFLOGSTRING("TSY: CMmConferenceCallGsmWcdmaExt::CallStatusChanged, statusChanged!! ");   
        }
TFLOGSTRING2("TSY: CMmConferenceCallGsmWcdmaExt::CallStatusChanged END, current conference extension iNewStatus:%d ", iNewStatus);

    return statusChanged;
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::SetGoOneToOneHandlingStarted
// Informs the Gsm extension if Go-One-To-One handling
// has started for any call.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmConferenceCallGsmWcdmaExt::SetGoOneToOneHandlingStarted(
    TBool aVal,
    TInt aCallId )
    {
    iGoOneToOneHandlingStarted = aVal;
    iGoOneToOneCallId = aCallId;
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::CheckConferenceCapability
// Check if conference call creation is possible.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmConferenceCallGsmWcdmaExt::CheckConferenceCapability(
    RMobileConferenceCall::TMobileConferenceStatus aStatus,
    CMmCallList* aCallList )
    {
TFLOGSTRING2("TSY: CMmConferenceCallGsmWcdmaExt::CheckConferenceCapability. aStatus:%d ", aStatus);     
    //Check if conference creation is possible. CC has to be in Idle state
    if ( RMobileConferenceCall::EConferenceIdle == aStatus  )
        {
        TUint8 connectedCount( 0 ); //how many calls are in active state
        TUint8 heldCount( 0 ); //how many calls are in hold state
        //number of calls in CallList
        TInt numberOfCallObjects = aCallList->GetNumberOfObjects();

        //check how many calls are in connected and held state
        for ( TInt i = 0; i < numberOfCallObjects; i++ )
            {
            CMmCallTsy* aMmCall = aCallList->GetMmCallByIndex( i );
            if ( aMmCall->MobileCallStatus() == 
                    RMobileCall::EStatusConnected )
                {
                //increment connected count
                connectedCount++;
                }
            else if ( aMmCall->MobileCallStatus() ==
                        RMobileCall::EStatusHold )
                {
                //increment held count
                heldCount++;
                }
            }

        //If caps were KCapsCreate and conference call creation is not anymore
        //possible, clear caps.
        TBool tryToClearConference( EFalse );

        if ( iMmConferenceCallTsy->Caps() == 
                RMobileConferenceCall::KCapsCreate )
            {
            tryToClearConference = ETrue;
            }

        //Check that exactly one call is on hold and one is active
        if ( ( 1 == connectedCount && 1 == heldCount ) && 
            !tryToClearConference )
            {
            //Conference call creation is possible -> inform Common part.
            iMmConferenceCallTsy->
                CompleteNotifyCapsChange( RMobileConferenceCall::KCapsCreate );
            }
        else if ( ( ( 1 == connectedCount && 0 == heldCount ) ||
            ( 0 == connectedCount && 1 == heldCount ) ) && 
            tryToClearConference ) 
            {
            //Conference call creation is not possible -> inform Common part.
            iMmConferenceCallTsy->CompleteNotifyCapsChange( KErrNone );
            }
        }
    }

#ifndef USING_CTSY_DISPATCHER

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::HangUpL
// This method terminates the whole conference call. All calls 
// participating in the conference call will be disconnected.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmConferenceCallGsmWcdmaExt::HangUpL(
    RMobileConferenceCall::TMobileConferenceStatus aStatus )
    {
    TInt ret( KErrAccessDenied );

    if ( aStatus != RMobileConferenceCall::EConferenceIdle )
        {
        //Close all calls that are part of the conference call.
        //Held call is not released if there is one...
        // no packed parameters for DOS call
        ret = iMmConferenceCallTsy->Phone()->MessageManager()->
            HandleRequestL( EMobileConferenceCallHangUp );
        }

    return ret;
    }

#endif //USING_CTSY_DISPATCHER

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::GetMobileCallInfo
// This method returns a current snapshot of the call information 
// associated with the call specified by the aIndex parameter. This works in 
// the following way: depending on the conference call status active/held the
// call object with the same status is searched from the call list. The index 
// defines which object's information is searched, for example if index is 2,
// second call object's information with the same status will be returned.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmConferenceCallGsmWcdmaExt::GetMobileCallInfo(
    TInt* aIndex,
    TDes8* aCallInfo,
    CMmCallList* aCallList,
    RMobileConferenceCall::TMobileConferenceStatus aConferenceStatus )
    {
    TInt ret( KErrNotFound );
    RMobileCall::TMobileCallStatus searchedStatus( RMobileCall::EStatusIdle );
    
    //check if we are trying to find active or held calls
    if ( aConferenceStatus == RMobileConferenceCall::EConferenceActive )
        {
        //active
        searchedStatus = RMobileCall::EStatusConnected;
        }
    else if ( aConferenceStatus == RMobileConferenceCall::EConferenceHold )
        {
        //held
        searchedStatus = RMobileCall::EStatusHold;
        }

    if ( searchedStatus != RMobileCall::EStatusIdle )
        {
        TInt counter( 0 );
        CMmCallTsy* mobileCall = NULL;

        //search through all objects in call list
        for ( TInt i = 0; i < aCallList->GetNumberOfObjects(); i++)
            {
            //get mobile call
            mobileCall = static_cast<CMmCallTsy*>(
                aCallList->GetObjectByIndex( i ) );
            //if call's status matches with searched status
            if ( mobileCall->MobileCallStatus() == searchedStatus && 
                    mobileCall->IsPartOfConference() )
                {
                //if index matches
                if ( counter == *aIndex )
                    {
                    //get mobile call info
                    mobileCall->FillMobileCallInfo( aCallInfo );
                    ret = KErrNone;
                    break;
                    }
                else
                    {
                    //else loop to next item in CallList with same status.
                    counter++;
                    }
                }
            }
        }
    
    return ret;
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::IsGoOneToOneSupported
// GoOneToOne is only valid if the MS is in GSM mode, the 
// selected call is a voice call and it is a member of an ongoing conference 
// call and there are no calls in Hold state.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmConferenceCallGsmWcdmaExt::IsGoOneToOneSupported(
    TInt  aCallId,
    RMobileConferenceCall::TMobileConferenceStatus aStatus,
    CMmCallList* aCallList )
    {
    TInt ret( KErrNotSupported );

    //The action is only valid if the MS is in GSM mode, the selected call 
    //is a voice call and it is a member of an ongoing conference call.
    if ( aStatus == RMobileConferenceCall::EConferenceActive )
        {
        CMmCallTsy* mobileCall = aCallList->GetMmCallById( aCallId );
        
        if (mobileCall != NULL)
            {
            if ( ( RMobilePhone::EVoiceService == mobileCall->CallMode() ) // is a voice call
                && ( RMobileCall::EStatusConnected ==  mobileCall->MobileCallStatus()) // is an active call
                && mobileCall->IsPartOfConference() ) // is a member of an ongoing conference call
                {
                ret = KErrNone;
	
                //Check that there are no held calls
                mobileCall = aCallList->GetMmCallByStatus( 
                                RMobileCall::EStatusHold );
	
                if ( mobileCall )
                    {
                    //held call found -> GoOneToOne not possible
                    ret = KErrNotSupported;
                    }
                }
            }
        }

    return ret;
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::HandleSwap
// This method checks when Swap is ready and can be completed.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TBool CMmConferenceCallGsmWcdmaExt::HandleSwap(
    RMobileConferenceCall::TMobileConferenceStatus aStatus,
    CMmCallList& aCallList )
    {
TFLOGSTRING2("TSY: CMmConferenceCallGsmWcdmaExt::HandleSwap. aStatus:%d ", aStatus);     
    TBool statusChanged( EFalse );

    //increment counter telling how many calls will still change state
    iNumberOfCallsToBeSwapped--;

    //if all have changed state
    if ( 0 == iNumberOfCallsToBeSwapped )
        {
        //if status was active
        if ( RMobileConferenceCall::EConferenceActive == aStatus )
            {
            //new status is hold
            iNewStatus = RMobileConferenceCall::EConferenceHold;
            statusChanged = ETrue;            
            }
        //else if status was hold
        else if ( RMobileConferenceCall::EConferenceHold == aStatus )
            {
            //new status id active
            iNewStatus = RMobileConferenceCall::EConferenceActive;
            statusChanged = ETrue;
            }
        //update caps
        UpdateCapsAfterSwap( aStatus, aCallList );
        }

    return statusChanged;
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::HandleAddCall
// This method checks when AddCall is ready and can be completed.
// It also updates the capability flags of the calls.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TBool CMmConferenceCallGsmWcdmaExt::HandleAddCall(
    RMobileConferenceCall::TMobileConferenceStatus aStatus,
    CMmCallList& aCallList,
    RMobileCall::TMobileCallStatus aNewStatus )
    {
TFLOGSTRING2("TSY: CMmConferenceCallGsmWcdmaExt::HandleAddCall. aStatus:%d ", aStatus); 
TFLOGSTRING2("TSY: CMmConferenceCallGsmWcdmaExt::HandleAddCall. aNewStatus:%d ", aNewStatus); 
    TBool statusChanged( EFalse );

    //Handle adding a call to conference call
    if ( RMobileCall::EStatusConnected == aNewStatus ||
         RMobileCall::EStatusIdle == aNewStatus )
        {
        TUint8 heldCount( 0 );

        //calculate how many calls are in hold state.
        for ( TInt i = 0; i < aCallList.GetNumberOfObjects(); i++ )
            {
            if ( aCallList.GetMmCallByIndex(i)->MobileCallStatus() 
                    == RMobileCall::EStatusHold )
                {
                //if a held call is found get out. There will be more active
                //status indications coming...
                heldCount++;
                break;
                }
            }
        //All calls have gone to active state
        if ( heldCount == 0 )
            {
            //This means that the conference call has gone from hold state
            //to active state in the add call process. AddCall can now be
            //completed.
            if ( RMobileConferenceCall::EConferenceHold == aStatus )
                {
                iNewStatus = RMobileConferenceCall::EConferenceActive;
                statusChanged = ETrue;
                }
            //Conference call status has not changed but we still have to 
            //complete the AddCall operation. 
            else 
                { 
                iMmConferenceCallTsy->CompleteAddCall( KErrNone ); 
                } 

            if ( RMobileConferenceCall::EConferenceBuilt == iCurrentGhostOperation ||
                 RMobileConferenceCall::EConferenceCallAdded == iCurrentGhostOperation )
                {
                TInt callIndex( 0 );
                CMmCallTsy* mmCall = aCallList.GetMmCallByIndex( callIndex );

                while ( mmCall ) 
                    { 
                    if ( !mmCall->IsPartOfConference() &&
                         ( mmCall->MobileCallStatus() == RMobileCall::EStatusConnected ||
                         mmCall->MobileCallStatus() == RMobileCall::EStatusHold) )
                        {
                        iMmConferenceCallTsy->CompleteNotifyConferenceEvent( 
                            mmCall->CallName(), 
                            RMobileConferenceCall::EConferenceCallAdded );
                        break;
                        }
                    callIndex++;
                    mmCall = aCallList.GetMmCallByIndex( callIndex );
                    }
                }

            //Call method that updates the caps of the joined calls
            UpdateCapsAfterJoin( aCallList );
            } 
        }
TFLOGSTRING2("TSY: CMmConferenceCallGsmWcdmaExt::HandleAddCall. statusChanged:%d ", statusChanged); 
    
    return statusChanged;
    }


// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::HandleCreateConference
// This method checks when CreateConference is ready and can be completed.
// This method checks that 2 active status indications are received
// as a response to the CreateConference request and when this is true, 
// CreateConference request can be completed.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TBool CMmConferenceCallGsmWcdmaExt::HandleCreateConference(
    CMmCallList& aCallList,
    TInt aCallId )
    {
    TBool statusChanged ( EFalse );
    CMmCallTsy* mmCall = NULL;

    //get mmcall
    mmCall = aCallList.GetMmCallById( aCallId );

    if ( mmCall )
        {
        //send call added event...
        iMmConferenceCallTsy->CompleteNotifyConferenceEvent( 
            mmCall->CallName(), RMobileConferenceCall::EConferenceCallAdded );

        //decrement counter..
        iCreateConferenceCounter--;

        //if 2 status indications are received
        if ( 0 == iCreateConferenceCounter )
            {
            //CreateConferece can be completed.
            iNewStatus = RMobileConferenceCall::EConferenceActive;
            statusChanged = ETrue;

            //Call method that updates the caps of the joined calls
            UpdateCapsAfterJoin( aCallList );
            } 
        }

    return statusChanged;
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::HandleCallRelease
// This method is called when status indications are received
// after HangUp is requested from Conference call object. First this method
// finds out which call object has gone to idle state. Then if there are
// less than 2 calls left in the remaining conference call, the rest of
// the conference call will be put to idle state as well (1 call can't be
// conference call from TSY's point of view).
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TBool CMmConferenceCallGsmWcdmaExt::HandleCallRelease(
		RMobileConferenceCall::TMobileConferenceStatus aStatus,
		CMmCallList& aCallList,
		RMobileCall::TMobileCallStatus aNewStatus,
		TInt aCallId )
	{
	TBool statusChanged( EFalse );
	TBool callFound( EFalse );
	CMmCallTsy* mmCall = NULL;

	TFLOGSTRING3("TSY: CMmConferenceCallGsmWcdmaExt::HandleCallRelease aNewStatus %d, aCallId %d",aNewStatus , aCallId );
	TFLOGSTRING2("TSY: CMmConferenceCallGsmWcdmaExt::HandleCallRelease Calls in CC %d",iMmConferenceCallTsy->NumberOfCallsInConference());

	//first find the call object which has gone to idle state
	for ( TInt i = 0; i < aCallList.GetNumberOfObjects(); i++ )
		{
		mmCall = aCallList.GetMmCallByIndex( i );

		if(mmCall)
			{
			TFLOGSTRING2("TSY: Previous Call ID: %d", mmCall->PreviousCallId() );
			if ( mmCall->PreviousCallId() == aCallId )
				{
				if ( 2 == iMmConferenceCallTsy->NumberOfCallsInConference() && mmCall->IsPartOfConference() &&
						iMmConferenceCallTsy->ServiceRequested( 
								CMmConferenceCallTsy::EMultimodeConferenceCallAddCall ) )
					{
					TFLOGSTRING("TSY: STOP handling this case");
					return EFalse;
					}
				mmCall->ResetPreviousCallId();
				callFound = ETrue;
				break;
				}
			}
		}

	//if call object has been found
	if ( callFound )
		{
		//add Join caps to the call that is not part of conference
		if ( KMaxCallsInConference == 
		iMmConferenceCallTsy->NumberOfCallsInConference() )
			{
			CMmCallGsmWcdmaExt* mmCallGsmWcdmaExt = NULL;
			RMobileCall::TMobileCallStatus status( RMobileCall::EStatusIdle );

			if ( RMobileConferenceCall::EConferenceActive == aStatus )
				{
				//get the held call
				status = RMobileCall::EStatusHold;
				}
			else if ( RMobileConferenceCall::EConferenceHold == aStatus )
				{
				//get the connected call
				status = RMobileCall::EStatusConnected;
				}

			if ( status != RMobileCall::EStatusIdle )
				{
				CMmCallTsy* nonIdleCall =
				aCallList.GetMmCallByStatus( status );

				if ( nonIdleCall )
					{
					// Fetch the active call extension
					mmCallGsmWcdmaExt = static_cast<CMmCallGsmWcdmaExt*>(
							nonIdleCall->ActiveCallExtension() );
					//add Join caps
					mmCallGsmWcdmaExt->AddGSMCallCaps( 
							RMobileCall::KCapsJoin );
					//complete caps change notification
					nonIdleCall->CompleteNotifyMobileCallCapsChange( 
							KErrNone );
					}
				}
			}

		if ( mmCall && mmCall->IsPartOfConference() )
			{    
			// if the released call was in the conference, send 
			// removed from conference indication
			iMmConferenceCallTsy->CompleteNotifyConferenceEvent( 
					mmCall->CallName(),
					RMobileConferenceCall::EConferenceCallRemoved );
			}

		//If there is only 1 call left in the CC, remove it. 1 call can't be
		//a conference call from MM API's point of view.
		if ( ( 1 == iMmConferenceCallTsy->NumberOfCallsInConference() ) &&
				!iMmConferenceCallTsy->ServiceRequested( 
						CMmConferenceCallTsy::EMultimodeConferenceCallHangUp ) )
			{
			RMobileCall::TMobileCallStatus callStatus( 
					RMobileCall::EStatusIdle );

			//send removed from conference also to the last call in the 
			// conference. Single call cannot be a conference call.
			if ( RMobileConferenceCall::EConferenceActive == aStatus )
				{
				//we are trying to find connected call
				callStatus = RMobileCall::EStatusConnected;

				//Special case when last member is on hold and CC Status is active at this 
				//point(2 members in CC and one is dropped and MO call is made at the same time)
				for ( TInt d = 0; d < aCallList.GetNumberOfObjects(); d++ )
					{
					CMmCallTsy* remainingCall = aCallList.GetMmCallByIndex(d);

					if( remainingCall->MobileCallStatus() == RMobileCall::EStatusHold )
						{
						callStatus = RMobileCall::EStatusHold;
						TFLOGSTRING("TSY: CMmConferenceCallGsmWcdmaExt::HandleCallRelease Call with Hold status found" );
						break;
						}	
					}

				}
			else if ( RMobileConferenceCall::EConferenceHold == aStatus )
				{
				//we are trying to find a held call
				callStatus = RMobileCall::EStatusHold;
				}
			//now search that call
			for ( TInt c = 0; c < aCallList.GetNumberOfObjects(); c++ )
				{
				CMmCallTsy* remainingCall = aCallList.GetMmCallByIndex(c);
				if ( remainingCall->MobileCallStatus() == callStatus )
					{
					iMmConferenceCallTsy->CompleteNotifyConferenceEvent( 
							remainingCall->CallName(), 
							RMobileConferenceCall::EConferenceCallRemoved );
					break;
					}                
				}

			UpdateCapsAfterCallRelease( aCallList );
			}

		//If there are no calls anymore in the CC, notify it...
		if ( 0 == iMmConferenceCallTsy->NumberOfCallsInConference() )
			{
			iNewStatus = RMobileConferenceCall::EConferenceIdle;
			statusChanged = ETrue;
			TName dummyName; //No calls left. Send EConferenceTerminate event. Use an empty placeholder name
			iMmConferenceCallTsy->CompleteNotifyConferenceEvent(dummyName,RMobileConferenceCall::EConferenceTerminated);
			}
		//if add call was going on and there was a call release
		else if ( iMmConferenceCallTsy->ServiceRequested( 
				CMmConferenceCallTsy::EMultimodeConferenceCallAddCall ) )
			{
			//conference call has not gone to idle state
			HandleAddCall( aStatus, aCallList, aNewStatus );
			}
		//if swap was going on and there was a call release
		else if ( iMmConferenceCallTsy->ServiceRequested( 
				CMmConferenceCallTsy::EMultimodeConferenceCallSwap ) )
			{
			//conference call has not gone to idle state
			HandleSwap( aStatus, aCallList );
			}
		}

	return statusChanged;
	}

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::HandleSingleCallControl
// This method is called when status indication is received
// and Swap, AddCall, CreateConference or HangUp is not requested from
// Conference call object. This means that client has requested hold or
// resume directly from single call object. If Hold has been requested 
// from single call participating conference call -> all calls in conference
// call will go to Hold state. Same applies also to the Resume command.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TBool CMmConferenceCallGsmWcdmaExt::HandleSingleCallControl(
    RMobileConferenceCall::TMobileConferenceStatus aStatus,
    RMobileCall::TMobileCallStatus aNewStatus )
    {
    TBool statusChanged( EFalse );

    if ( !iCallControlStarted )
        {   
        //save count, how many indications should be received
        iCallsToBeControlled = iMmConferenceCallTsy->
            NumberOfCallsInConference();
        //Don't come here before all calls have changed their status
        iCallControlStarted = ETrue;
        }

    //if CC is in Hold status and we get Active status indication
    if ( RMobileCall::EStatusConnected == aNewStatus &&
        RMobileConferenceCall::EConferenceHold == aStatus )
        {
        //one call in Conference call has changed its status
        iCallsToBeControlled--;
        }
    //if CC is in Active status and we get Hold status indication
    else if ( RMobileCall::EStatusHold == aNewStatus &&
        RMobileConferenceCall::EConferenceActive == aStatus )
        {
        //one call in Conference call has changed its status
        iCallsToBeControlled--;
        }

    //Have all calls in Conference call changed their status?
    if ( 0 == iCallsToBeControlled )
        {
        //if CC was originally in Hold status we have changed to active state
        if ( RMobileConferenceCall::EConferenceHold == aStatus )
            {
            iNewStatus = RMobileConferenceCall::EConferenceActive;
            }
        //if CC was originally in Active status we have changed to hold state
        else if ( RMobileConferenceCall::EConferenceActive == aStatus )
            {
            iNewStatus = RMobileConferenceCall::EConferenceHold;
            }
        //reset flag
        iCallControlStarted = EFalse;
   
        statusChanged = ETrue;
        }   

    return statusChanged;
    }
    
// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::HandleGoOneToOne
// This method checks when GoOneToOne is ready and can be completed.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TBool CMmConferenceCallGsmWcdmaExt::HandleGoOneToOne(
    CMmCallList& aCallList,
    TInt aCallId )
    {
    TBool statusChanged( EFalse );
    CMmCallTsy* mmCall = NULL;

    // check if the call placed on hold is the one to go one to one with
    // if so, cancel one to one
    if (aCallId == iGoOneToOneCallId)
        {
        mmCall = aCallList.GetMmCallById( iGoOneToOneCallId );
        if ( mmCall )
            {
            // failure of the Go-One-To-One operation
            reinterpret_cast<CMmVoiceCallTsy*>( mmCall )->CompleteGoOneToOne(
                KErrNotReady );
            }
        
        iGoOneToOneHandlingStarted = EFalse;
        iGoOneToOneCallId = -1;
        iCallControlStarted = EFalse;
        return statusChanged;
        }

    if ( !iCallControlStarted )
        {   
        //save count, how many indications should be received. All but one 
        //call (the one that was splitted) should go to hold state.
        iCallsToBeControlled = 
            iMmConferenceCallTsy->NumberOfCallsInConference() - 1;

        //Conference call will go to Idle state
        if ( 1 == iCallsToBeControlled )
            {
            for ( TInt i = 0; i < aCallList.GetNumberOfObjects(); i++ )
                {
                mmCall = aCallList.GetMmCallByIndex( i );

                if ( RMobileCall::EStatusConnected == mmCall->MobileCallStatus() 
                    || RMobileCall::EStatusHold == mmCall->MobileCallStatus() )
                    {
                    // The call removed notification event for the call which has
                    // been split gets completed later when the split event is
                    // completed. This if stops extra call removed event from being completed.
                    if (mmCall->CallId() != iGoOneToOneCallId)
                    	{
#ifdef USING_CTSY_DISPATCHER
						iMmConferenceCallTsy->CompleteNotifyConferenceEvent(
							mmCall->CallName(),
							RMobileConferenceCall::EConferenceCallRemoved );
#else // USING_CTSY_DISPATCHER
                    iMmConferenceCallTsy->CompleteNotifyConferenceEvent( 
                        mmCall->CallName(), 
                        RMobileConferenceCall::EConferenceCallRemoved );
#endif // USING_CTSY_DISPATCHER
                    	}
   
                    CMmCallGsmWcdmaExt* mmCallGsmWcdmaExt = 
                        static_cast<CMmCallGsmWcdmaExt*>( 
                            mmCall->ActiveCallExtension() );

                    TUint32 caps = RCall::KCapsHangUp;
                    caps |= RMobileCall::KCapsJoin |
                        RMobileCall::KCapsSwap |
                        RMobileCall::KCapsTransfer;

                    mmCallGsmWcdmaExt->AddGSMCallCaps( caps );
                    mmCallGsmWcdmaExt->RemoveGSMCallCaps( 
                        RMobileCall::KCapsOneToOne );

                    mmCall->CompleteNotifyMobileCallCapsChange( KErrNone );  
                    }
                }

            //new status is idle (there is no conference anymore)
            iNewStatus = RMobileConferenceCall::EConferenceIdle;
            statusChanged = ETrue;
            }

        // Call control is going on, i.e. we are waiting for other calls'
        // status indications
        iCallControlStarted = ETrue;
        }      

    //decrement counter telling how many calls will still change state
    iCallsToBeControlled--;

    //All conference related call object have changed their state. Remove 
    //go-one-to-one call object from conference call.
    if ( iCallsToBeControlled == 0 && iCallControlStarted )
        {
        if ( !statusChanged )
            {
            // If conference is created with two other parties, conference
            // is destructed (status is set to EConferenceIdle, see above)
            iNewStatus = RMobileConferenceCall::EConferenceHold;
            statusChanged = ETrue;
            }
        iCallControlStarted = EFalse;
        iGoOneToOneHandlingStarted = EFalse;

        mmCall = aCallList.GetMmCallById( iGoOneToOneCallId );
        
        iGoOneToOneCallId = -1;

        if ( mmCall )
            {
            iMmConferenceCallTsy->CompleteNotifyConferenceEvent( 
                    mmCall->CallName(), 
                    RMobileConferenceCall::EConferenceCallRemoved );  
                    
            iMmConferenceCallTsy->CompleteNotifyConferenceEvent( 
                    mmCall->CallName(), 
                    RMobileConferenceCall::EConferenceSplit );  

            CMmCallGsmWcdmaExt* mmCallGsmWcdmaExt = 
                static_cast<CMmCallGsmWcdmaExt*>( 
                    mmCall->ActiveCallExtension() );
                    
            mmCallGsmWcdmaExt->AddGSMCallCaps( RMobileCall::KCapsJoin );
            mmCallGsmWcdmaExt->AddGSMCallCaps( RMobileCall::KCapsHangUp );
            mmCallGsmWcdmaExt->RemoveGSMCallCaps( RMobileCall::KCapsOneToOne );  
            
            mmCall->CompleteNotifyMobileCallCapsChange( KErrNone );        

            // successful complete of the Go-One-To-One operation
            reinterpret_cast<CMmVoiceCallTsy*>( mmCall )->CompleteGoOneToOne(
                KErrNone );
            }
        }
    //Update caps only if call is still part of conference call
    else if ( iCallControlStarted && iGoOneToOneCallId != aCallId )
        {        
        mmCall = aCallList.GetMmCallById( aCallId );

        if ( NULL != mmCall )
            {
            CMmCallGsmWcdmaExt* mmCallGsmWcdmaExt = 
                static_cast<CMmCallGsmWcdmaExt*>(
                    mmCall->ActiveCallExtension() );

            mmCallGsmWcdmaExt->AddGSMCallCaps( RMobileCall::KCapsHangUp );
            mmCallGsmWcdmaExt->RemoveGSMCallCaps( 
                RMobileCall::KCapsOneToOne );

            mmCall->CompleteNotifyMobileCallCapsChange( KErrNone );
            }
        }

    return statusChanged;
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::GetNewStatus
// Called by common Conference call object to get the current
// conference call status. It will be copied to aNewStatus.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmConferenceCallGsmWcdmaExt::GetNewStatus(
    RMobileConferenceCall::TMobileConferenceStatus* aNewStatus )
    {
TFLOGSTRING2("TSY: CMmConferenceCallGsmWcdmaExt::GetNewStatus. iNewStatus:%d ", iNewStatus );     
    //copy new status
    *aNewStatus = iNewStatus;
    //delete new status from GSM extension
    iNewStatus = RMobileConferenceCall::EConferenceIdle;

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::ResetAttributes
// Resets internal attributes.
// ---------------------------------------------------------------------------
//
void CMmConferenceCallGsmWcdmaExt::ResetAttributes()
    {
TFLOGSTRING("TSY: CMmConferenceCallGsmWcdmaExt::ResetAttributes. " );     
    //Flag telling if this is not the first hold/active status indication
    //caused by client asking hold/resume for a single call.
    iCallControlStarted = EFalse;
    //Counter telling how many calls should still change their state before
    //Conference call changes its' state.
    iCallsToBeControlled = 0;
    //Counter telling when Create conference is ready to be completed 
    iCreateConferenceCounter = 0;
    //New conference call status
    iNewStatus = RMobileConferenceCall::EConferenceIdle;
    //Count, how many calls are to be swapped
    iNumberOfCallsToBeSwapped = 0;
    //Flag telling if GoOneToOne handling is going on.
    iGoOneToOneHandlingStarted = EFalse;
    //Call id for which GoOneToOne handling is going on.
    iGoOneToOneCallId = -1;
    //Operation initiated bypassing the ETel (ghost operetion).
    iCurrentGhostOperation = -1;
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::UpdateCapsAfterJoin
// Updates call capabilities of all calls after a Join operation
// has been executed (CreateConference or AddCall).
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmConferenceCallGsmWcdmaExt::UpdateCapsAfterJoin(
    CMmCallList& aCallList ) const
    {
    //update flags of all joined calls
    for ( TInt i = 0; i < aCallList.GetNumberOfObjects(); i++ )
        {
        //Get call object
        CMmCallTsy* mmCall = aCallList.GetMmCallByIndex(i);

        if ( mmCall )
            {
            if ( mmCall->MobileCallStatus() == RMobileCall::EStatusConnected )
                {
                // Fetch the active call extension
                CMmCallGsmWcdmaExt* mmCallGsmWcdmaExt = 
                    static_cast<CMmCallGsmWcdmaExt*>(
                        mmCall->ActiveCallExtension() );

                //set caps to be removed;
                TUint32 caps =  
                    RMobileCall::KCapsJoin 
                    | RMobileCall::KCapsSwap;
                //remove Join and Swap caps
                mmCallGsmWcdmaExt->RemoveGSMCallCaps( caps );
                //Add GoOneToOne caps
                mmCallGsmWcdmaExt->AddGSMCallCaps( 
                    RMobileCall::KCapsOneToOne );
                //complete caps change notification
                mmCall->CompleteNotifyMobileCallCapsChange( KErrNone );
                }
            }
        }
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::UpdateCapsAfterCallRelease
// Updates call capabilities of all calls after a call participating in
// the conference call has gone to idle state.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmConferenceCallGsmWcdmaExt::UpdateCapsAfterCallRelease(
    CMmCallList& aCallList ) const
    {
    TUint32 caps( 0 );

    //try to find connected call
    CMmCallTsy* connectedCall = aCallList.GetMmCallByStatus( 
        RMobileCall::EStatusConnected );
    //try to find a held call
    CMmCallTsy* heldCall = aCallList.GetMmCallByStatus( 
        RMobileCall::EStatusHold );

    CMmCallGsmWcdmaExt* mmCallGsmWcdmaExt = NULL;

    if ( connectedCall )
        {
        // Fetch the active call extension
        mmCallGsmWcdmaExt = static_cast<CMmCallGsmWcdmaExt*>(
            connectedCall->ActiveCallExtension() );

        //add HangUp caps
        mmCallGsmWcdmaExt->AddGSMCallCaps( 
            RMobileCall::KCapsHangUp );

        //update caps of connected call
        if ( heldCall )
            {
            //set caps to be added;
            caps = RMobileCall::KCapsJoin 
                | RMobileCall::KCapsTransfer
                | RMobileCall::KCapsSwap;
            //add Join, Transfer and Swap caps
            mmCallGsmWcdmaExt->AddGSMCallCaps( caps );
            }
        else
            {
            //set caps to be removed;
            caps = RMobileCall::KCapsJoin 
                | RMobileCall::KCapsTransfer
                | RMobileCall::KCapsSwap;
            //remove Join, Transfer and Swap caps
            mmCallGsmWcdmaExt->RemoveGSMCallCaps( caps );
            }

        //complete caps change notification
        connectedCall->CompleteNotifyMobileCallCapsChange( KErrNone );
        }

    if ( heldCall )
        {
        // Fetch the active call extension
        mmCallGsmWcdmaExt = static_cast<CMmCallGsmWcdmaExt*>(
            heldCall->ActiveCallExtension() );

        //add HangUp caps
        mmCallGsmWcdmaExt->AddGSMCallCaps( 
            RMobileCall::KCapsHangUp );

        //update caps of connected call
        if ( connectedCall )
            {
            //set caps to be added;
            caps = RMobileCall::KCapsJoin 
                | RMobileCall::KCapsTransfer
                | RMobileCall::KCapsSwap;
            //add Join, Transfer and Swap caps
            mmCallGsmWcdmaExt->AddGSMCallCaps( caps );
            }
        else
            {
            //set caps to be removed;
            caps = RMobileCall::KCapsJoin 
                | RMobileCall::KCapsTransfer
                | RMobileCall::KCapsSwap;
            //remove Join, Transfer and Swap caps
            mmCallGsmWcdmaExt->RemoveGSMCallCaps( caps );
            }

        //complete caps change notification
        heldCall->CompleteNotifyMobileCallCapsChange( KErrNone );
        }
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::UpdateCapsAfterSwap
// Updates call capabilities of all calls after a Swap operation has
// been executed.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmConferenceCallGsmWcdmaExt::UpdateCapsAfterSwap(
    RMobileConferenceCall::TMobileConferenceStatus aStatus,
    CMmCallList& aCallList ) const
    {
    CMmCallTsy* mmCall = NULL;
    CMmCallGsmWcdmaExt* mmCallGsmWcdmaExt = NULL;

    //if status was active
    if ( aStatus == RMobileConferenceCall::EConferenceActive )
        {
        //update caps of all calls participating conference
        //loop through all call objects searching the held calls
        for ( TInt i = 0; i < aCallList.GetNumberOfObjects(); i++ )
            {
            mmCall = aCallList.GetMmCallByIndex( i );

            if ( mmCall->MobileCallStatus() == RMobileCall::EStatusHold )
                {
                // Fetch the active call extension
                mmCallGsmWcdmaExt = static_cast<CMmCallGsmWcdmaExt*>(
                    mmCall->ActiveCallExtension() );

                //remove GoOneToOne caps
                mmCallGsmWcdmaExt->RemoveGSMCallCaps( 
                    RMobileCall::KCapsOneToOne );
                //complete caps change notification
                mmCall->CompleteNotifyMobileCallCapsChange( KErrNone );
                }
            }
        }
    //else if status was hold
    else if ( aStatus == RMobileConferenceCall::EConferenceHold )
        {
        TInt numberOfNonIdleCalls( 0 );

        //find out the number of non idle calls
        for ( TInt i = 0; i < aCallList.GetNumberOfObjects(); i++ )
            {
            mmCall = aCallList.GetMmCallByIndex( i );
            if ( mmCall->MobileCallStatus() != RMobileCall::EStatusIdle )
                {
                numberOfNonIdleCalls++;
                }
            }

        //check that all non idle calls belong to conference call
        //-> GoOneToOne can be activated.
        if ( numberOfNonIdleCalls <=
            iMmConferenceCallTsy->NumberOfCallsInConference() )
            {
            //update caps of all calls participating conference
            //loop through all call objects searching the held calls
            for ( TInt i = 0; i < aCallList.GetNumberOfObjects(); i++ )
                {
                mmCall = aCallList.GetMmCallByIndex( i );

                if ( mmCall->MobileCallStatus() 
                    == RMobileCall::EStatusConnected )
                    {
                    // Fetch the active call extension
                    mmCallGsmWcdmaExt = static_cast<CMmCallGsmWcdmaExt*>(
                        mmCall->ActiveCallExtension() );

                    //add GoOneToOne caps
                    mmCallGsmWcdmaExt->AddGSMCallCaps( 
                        RMobileCall::KCapsOneToOne );
                    //complete caps change notification
                    mmCall->CompleteNotifyMobileCallCapsChange( KErrNone );
                    }
                }
            }
        }
    }

// ---------------------------------------------------------------------------
// CMmConferenceCallGsmWcdmaExt::CompleteNotifyConferenceEvent
// Informs the Gsm extension if there is conference call
// operation performed that has been initiated bypassing the ETel.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmConferenceCallGsmWcdmaExt::CompleteNotifyConferenceEvent(
    CMmDataPackage* aDataPackage )
    {
    TInt callId( -1 );
    RMobilePhone::TMobileService callMode(
        RMobilePhone::EServiceUnspecified );
    TInt confEvent = -1;

    CCallDataPackage* callDataPackage = 
        reinterpret_cast<CCallDataPackage*>(aDataPackage);

    callDataPackage->GetCallIdAndMode( callId, callMode );
    callDataPackage->UnPackData( confEvent );

    //get current conference call status
    RMobileConferenceCall::TMobileConferenceStatus status 
            = iMmConferenceCallTsy->Status();
TFLOGSTRING2("TSY: CMmConferenceCallGsmWcdmaExt::CompleteNotifyConferenceEvent. iMmConferenceCallTsy->Status():%d ", status );

    switch( confEvent )
        {
        case RMobileConferenceCall::EConferenceBuilt:
            //if createConference has not been requested using ETel API
            //and conference status is idle
            if ( RMobileConferenceCall::EConferenceIdle == status && 
                !iMmConferenceCallTsy->ServiceRequested( CMmConferenceCallTsy::
                    EMultimodeConferenceCallCreateConference ) )
                {
TFLOGSTRING("TSY: CMmConferenceCallGsmWcdmaExt::CompleteNotifyConferenceEvent - Build");
                //We have to get 2 active status indications before the 
                //conference has really gone to active state.
                iCreateConferenceCounter = 2;
                iCurrentGhostOperation = confEvent;
                }
            //if addCall has not been requested using ETel API
            //and conference status is Hold or Active
            else if ( RMobileConferenceCall::EConferenceIdle != status &&
                !iMmConferenceCallTsy->ServiceRequested( CMmConferenceCallTsy::
                    EMultimodeConferenceCallAddCall ) )
                {
TFLOGSTRING("TSY: CMmConferenceCallGsmWcdmaExt::CompleteNotifyConferenceEvent - Build/Add");
                iCurrentGhostOperation = confEvent;
                }
            break;
        case RMobileConferenceCall::EConferenceCallAdded:
            //if addCall has not been requested using ETel API
            //and conference status is Hold or Active
            if ( RMobileConferenceCall::EConferenceIdle != status &&
                !iMmConferenceCallTsy->ServiceRequested( CMmConferenceCallTsy::
                    EMultimodeConferenceCallAddCall ) )
                {
TFLOGSTRING("TSY: CMmConferenceCallGsmWcdmaExt::CompleteNotifyConferenceEvent - Add");
                iCurrentGhostOperation = confEvent;
                }
            break;
        case RMobileConferenceCall::EConferenceSwapped:
            //if swap has not been requested using ETel API
            if ( RMobileConferenceCall::EConferenceIdle != status &&
                !iMmConferenceCallTsy->ServiceRequested( 
                CMmConferenceCallTsy::EMultimodeConferenceCallSwap ) )
                {
TFLOGSTRING("TSY: CMmConferenceCallGsmWcdmaExt::CompleteNotifyConferenceEvent - Swap");
                iNumberOfCallsToBeSwapped 
                    = iMmConferenceCallTsy->NumberOfCallsInConference();

                iCurrentGhostOperation = confEvent;
                }
            break;
        //GoOneToOne has been requested
        case RMobileConferenceCall::EConferenceSplit:
            if ( !iGoOneToOneHandlingStarted )
                {
TFLOGSTRING("TSY: CMmConferenceCallGsmWcdmaExt::CompleteNotifyConferenceEvent - Split");
                iGoOneToOneHandlingStarted = ETrue;
                iCurrentGhostOperation = confEvent;
                iGoOneToOneCallId = callId;
                }
            break;
        default:
TFLOGSTRING("TSY: CMmConferenceCallGsmWcdmaExt::CompleteNotifyConferenceEvent - No Actions");
            break;
        }
    }


//  End of File 
