// ---------------------------------------------------------------------------
// 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

            CMmCallTsy* mmExistingCall = NULL;
            TInt existingCallId;
            __DEBUG_ONLY(TBool callFound = EFalse;)
            TInt numOfObjects = aCallList->GetNumberOfObjects();            
            for ( TInt i = 0; i < numOfObjects; i++ )
            	{
            	mmExistingCall = aCallList->GetMmCallByIndex(i);
            	if ( mmExistingCall->IsPartOfConference() )
            		{
            		__DEBUG_ONLY(callFound = ETrue;)
            		existingCallId = mmExistingCall->CallId();
            		break;
            		}            		
// -----------------------------------------------------------------------------
// CMmConferenceCallMessHandler::CallControlInd
// Breaks a CALL_CONTROL_IND ISI-message. Completes failed
// CreateConference, AddCall or Swap API request if there is a cause sub
// block in this response. In case that this message contains Split operation
// sub block, inform ConferenceCallTsy that GoOneToOne handling has started
// -----------------------------------------------------------------------------
//
void CMmConferenceCallMessHandler::CallControlInd(
    const TIsiReceiveC& aIsiMsg )
    {
TFLOGSTRING("TSY: CMmConferenceCallMessHandler::CallControlInd");
OstTrace0( TRACE_NORMAL,  CMMCONFERENCECALLMESSHANDLER_CALLCONTROLIND_TD, "CMmConferenceCallMessHandler::CallControlInd" );

    TUint sbStartOffSet( 0 );

    // Try to find CALL_MODEM_SB_CAUSE subblock. If found something has gone wrong
    if( KErrNone == aIsiMsg.FindSubBlockOffsetById(
        ISI_HEADER_SIZE + SIZE_CALL_MODEM_CONTROL_IND,
        CALL_MODEM_SB_CAUSE,
        EIsiSubBlockTypeId8Len8,
        sbStartOffSet ) )
        {
        // CALL_MODEM_SB_CAUSE sub block found, something has gone wrong.
        // Get cause type
        TUint8 causeType( aIsiMsg.Get8bit(
            sbStartOffSet + CALL_MODEM_SB_CAUSE_OFFSET_CAUSETYPE ) );
        // Get cause value
        TUint8 causeValue( aIsiMsg.Get8bit(
            sbStartOffSet + CALL_MODEM_SB_CAUSE_OFFSET_CAUSE ) );

        // Get Symbian OS error value
        TInt result( CMmStaticUtility::CSCauseToEpocError(
            PN_MODEM_CALL,
            causeType,
            causeValue ) );

        // If last operation was build, CreateConference or AddCall was asked
        if ( CALL_MODEM_OP_CONFERENCE_BUILD == iLastOperation )
            {
            // Has CreateConference been requested last.
            if ( iIsCreateConference )
                {
                // Complete with error
                iMessageRouter->Complete(
                    EMobileConferenceCallCreateConference,
                    result);
                // Reset flag
                iIsCreateConference = EFalse;
                }
            else
                {
                // Must be response to AddCall request
                iMessageRouter->Complete(
                    EMobileConferenceCallAddCall,
                    result );
                }
            iLastOperation = 0;
            }
        // if last operation was hold or retrieve
        else if ( CALL_MODEM_OP_HOLD == iLastOperation ||
            CALL_MODEM_OP_RETRIEVE == iLastOperation )
            {
            // Complete swap with error
            iMessageRouter->Complete(
                EMobileConferenceCallSwap,
                result );
            }
        // No else
        }
    // Successful operation handling for operations
    // Initiated bypassing the ETel (ghost operetion).
    else if ( !iIsCreateConference && 0 == iLastOperation )
        {
        TUint8 callOperation( 0 );
        // Get call Id (three bits (1-3) contain unique call ID)
        TInt uniqueCallId( static_cast<TInt>( aIsiMsg.Get8bit(
            ISI_HEADER_SIZE + CALL_MODEM_CONTROL_IND_OFFSET_CALLID )
            & KMaskBits1to3 ) );

        // Get call operation sub block
        if ( KErrNone == aIsiMsg.FindSubBlockOffsetById(
            ISI_HEADER_SIZE + CALL_MODEM_CONTROL_IND_OFFSET_OPERATION,
            CALL_MODEM_SB_OPERATION,
            EIsiSubBlockTypeId8Len8,
            sbStartOffSet ) )
            {
            TInt symbianConferenceEvent( -1 );
            // Get call operation
            callOperation = aIsiMsg.Get8bit(
                sbStartOffSet + CALL_MODEM_SB_OPERATION_OFFSET_OPERATION );

TFLOGSTRING2("TSY: CMmConferenceCallMessHandler::CallControlInd - Call operation: %d", callOperation);
OstTraceExt1( TRACE_NORMAL,  DUP1_CMMCONFERENCECALLMESSHANDLER_CALLCONTROLIND_TD, "CMmConferenceCallMessHandler::CallControlInd;callOperation=%hhu", callOperation );
            // Purpose of this case is to prepare handling of externally
            // controlled conference call
            switch ( callOperation )
                {
                case CALL_MODEM_OP_CONFERENCE_BUILD:
                    {
                    symbianConferenceEvent =
                        RMobileConferenceCall::EConferenceBuilt;
                    break;
                    }
                case CALL_MODEM_OP_HOLD:
                case CALL_MODEM_OP_SWAP:
                    {
                    symbianConferenceEvent =
                        RMobileConferenceCall::EConferenceSwapped;
                    break;
                    }
                case CALL_MODEM_OP_CONFERENCE_SPLIT:
                    {
                    symbianConferenceEvent =
                        RMobileConferenceCall::EConferenceSplit;
                    break;
                    }
                default:
                    {
                    // Nothing to do
                    break;
                    }
                }

            // Update the information to Conference call
            if ( 0 <= symbianConferenceEvent )
                {
                // Create call package
                CCallDataPackage callData;
                // Pack the data for sending to the manager
                callData.SetCallIdAndMode(
                    uniqueCallId,
                    RMobilePhone::EVoiceService );
                // Pack conference event
                callData.PackData( &symbianConferenceEvent );
                // Pass call information to the Symbian OS layer
                // complete mobile call info change
                iMessageRouter->Complete(
                    EMobileConferenceCallNotifyConferenceEvent,
                    &callData,
                    KErrNone );
                }
            // No else
            }
        // No else
        }
    // No else

    iIsCreateConference = EFalse;
    iLastOperation = 0;
    }