connectionmonitoring/connmon/connectionmonitor/src/CCsdFax.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 18 Jan 2010 20:33:49 +0200
changeset 2 086aae6fc07e
parent 0 5a93021fdf25
permissions -rw-r--r--
Revision: 201001 Kit: 201003

/*
* Copyright (c) 2002-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:  Provides information on CSD fax calls.
*
*/

#include <mmtsy_names.h>
#include <rmmcustomapi.h>
#include "ConnMonServ.h"
#include "ConnMonIAP.h"
#include "CEventQueue.h"
#include "CCsdFax.h"
#include "log.h"

// -----------------------------------------------------------------------------
// CCsdFax::CCsdFax
// -----------------------------------------------------------------------------
//
CCsdFax::CCsdFax(
        CConnMonServer* aServer,
        RTelServer* aTelServer,
        RMobilePhone* aMobilePhone )
        :
        iServer( aServer ),
        iTelServer( aTelServer ),
        iMobilePhone( aMobilePhone )
    {
    }

// -----------------------------------------------------------------------------
// CCsdFax::ConstructL
// -----------------------------------------------------------------------------
//
void CCsdFax::ConstructL()
    {
    //LOGENTRFN("CCsdFax::ConstructL()")
    // Open "Data" line
    TInt ret = iLine.Open( *iMobilePhone, KMmTsyDataLineName );

    if ( ret != KErrNone )
        {
        LOGIT("CCsdFax: Could not open data line.")
        return;
        }
    else
        {
        iState = ELineOpen;
        }

    // Start external connection Up notifier
    if ( iConnUpNotifier == 0 )
        {
        iConnUpNotifier = new( ELeave ) CCsdFaxUpNotifier(
                this,
                iServer,
                iMobilePhone,
                iLine);
        iConnUpNotifier->Construct();
        iConnUpNotifier->Receive();
        }

    // Start external connection Up notifier
    if ( iStatusNotifier == 0 )
        {
        iStatusNotifier = new( ELeave ) CCsdStatusNotifier(
                this,
                iServer );
        iStatusNotifier->Construct();
        }
    //LOGEXITFN("CCsdFax::ConstructL()")
    }

// Destructor
CCsdFax::~CCsdFax()
    {
    if ( iConnUpNotifier != 0 )
        {
        iConnUpNotifier->Cancel();
        delete iConnUpNotifier;
        iConnUpNotifier = 0;
        }

    if ( iStatusNotifier != 0 )
        {
        iStatusNotifier->Cancel();
        delete iStatusNotifier;
        iStatusNotifier = 0;
        }

    if ( iState == ECallOpen )
        {
        CloseCall();
        }

    if ( iState > EModuleClosed )
        {
        iLine.Close();
        }
    }

// -----------------------------------------------------------------------------
// CCsdFax::OpenCall
// -----------------------------------------------------------------------------
//
TInt CCsdFax::OpenCall( const TDes& aName )
    {
    if ( iState == ECallOpen )
        {
        CloseCall();
        }

    RTelServer::TPhoneInfo phoneInfo;
    TInt err = iTelServer->GetPhoneInfo( 0, phoneInfo );

    if ( err != KErrNone )
        {
        return err;
        }

    iCsdFaxCallName.Copy( phoneInfo.iName );
    iCsdFaxCallName.Append( KDoubleColon );
    iCsdFaxCallName.Append( KMmTsyDataLineName );
    iCsdFaxCallName.Append( KDoubleColon );
    iCsdFaxCallName.Append( aName );

    err = iCall.OpenExistingCall( *iTelServer, iCsdFaxCallName );

    if ( KErrNone == err )
        {
        iState = ECallOpen;

        // Start status event watcher
        if ( !iStatusNotifier->IsActive() )
            {
            iStatusNotifier->Start( &iCall );
            }
        }

    return err;
    }

// -----------------------------------------------------------------------------
// CCsdFax::CloseCall
// -----------------------------------------------------------------------------
//
void CCsdFax::CloseCall()
    {
    if ( iStatusNotifier != 0 )
        {
        iStatusNotifier->Cancel();
        }

    iCall.Close();
    iState = ELineOpen;

    iCsdFaxCallName.FillZ();
    iCsdFaxCallName.Zero();
    }

// -----------------------------------------------------------------------------
// CCsdFax::IsValid
// -----------------------------------------------------------------------------
//
TBool CCsdFax::IsValid()
    {
    if ( iState == ECallOpen )
        {
        return ETrue;
        }
    else
        {
        return EFalse;
        }
    }

// -----------------------------------------------------------------------------
// CCsdFax::FindCall
// -----------------------------------------------------------------------------
//
TInt CCsdFax::FindCall()
    {
    TInt ret( KErrNone );
    TInt countCalls( 0 );

    if ( iState == ECallOpen )
        {
        return KErrNone;
        }
    else if ( iState < ELineOpen )
        {
        return KErrNotFound;
        }

    // Enumerate calls on data line
    ret = iLine.EnumerateCall( countCalls );

    if ( ret != KErrNone )
        {
        return ret;
        }
    else if ( countCalls == 0 )
        {
        return KErrNotFound;
        }

    RMmCustomAPI customApi;
    RMmCustomAPI::TCallOrigin origin;

    ret = customApi.Open( *iMobilePhone );

    if ( ret != KErrNone )
        {
        return ret;
        }

    // Get call info
    for ( TInt j = 0; j < countCalls; j++ )
        {
        RLine::TCallInfo callInfo;

        ret = iLine.GetCallInfo( j, callInfo );
        if ( ret != KErrNone )
            {
            customApi.Close();
            return ret;
            }

        customApi.CallOrigin( callInfo.iCallName, origin );

        // TF
        if ( origin == RMmCustomAPI::EOutsider )
            {
            ret = KErrNone;
            OpenCall( callInfo.iCallName );
            break;
            }
        else
            {
            ret = KErrNotFound;
            }
        }

    customApi.Close();
    return ret;
    }

// -----------------------------------------------------------------------------
// CCsdFax::GetBearer
// -----------------------------------------------------------------------------
//
TInt CCsdFax::GetBearer( TInt& aBearer, TBearerInfo& aBearerInfo ) const
    {
    TInt ret( KErrNone );
    RMobileCall::TMobileCallStatus mobileCallStatus;

    if ( iState < ECallOpen )
        {
        return KErrNotFound;
        }

    // Is network WCDMA
    RMobilePhone::TMobilePhoneNetworkMode mode;
    ret = iMobilePhone->GetCurrentMode( mode );

    if ( ret != KErrNone )
        {
        return ret;
        }
    if ( mode == RMobilePhone::ENetworkModeWcdma )
        {
        aBearer = EBearerExternalWcdmaCSD;
        aBearerInfo.iBearer = EBearerInfoWcdmaCSD;
        aBearerInfo.iInternal = EFalse;

        return KErrNone;
        }

    ret = iCall.GetMobileCallStatus( mobileCallStatus );

    if ( ret != KErrNone )
        {
        return ret;
        }

    aBearer = EBearerExternalCSD;
    aBearerInfo.iBearer = EBearerInfoCSD;
    aBearerInfo.iInternal = EFalse;

    if ( mobileCallStatus != RMobileCall::EStatusIdle )
        {
        RMobileCall::TMobileCallHscsdInfoV1 hscsdInfo;
        RMobileCall::TMobileCallHscsdInfoV1Pckg hscsdInfoPckg( hscsdInfo );

        for ( TInt a = 0; a < KBearerQueryCount; a++ )
            {
            ret = iCall.GetCurrentHscsdInfo( hscsdInfoPckg );

            if ( ret != KErrEtelCallNotActive )
                {
                break;
                }

            User::After( KBearerQueryTimeout );
            }

        if ( KErrNone == ret )
            {
            if ( hscsdInfo.iAiur != RMobileCall::EAiurBpsUnspecified )
                {
                aBearer = EBearerExternalHSCSD;
                aBearerInfo.iBearer = EBearerInfoHSCSD;
                }
            }
        }
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CCsdFax::GetStatus
// -----------------------------------------------------------------------------
//
TInt CCsdFax::GetStatus( TInt& aStatus ) const
    {
    TInt ret( KErrNone );

    if ( iState < ECallOpen )
        {
        return KErrNotFound;
        }

    RMobileCall::TMobileCallStatus mobileCallStatus;
    ret = iCall.GetMobileCallStatus( mobileCallStatus );

    if ( ret != KErrNone )
        {
        return ret;
        }

    aStatus = mobileCallStatus;
    ret = MapStatus( aStatus );

    return ret;
    }

// -----------------------------------------------------------------------------
// CCsdFax::MapStatus
// -----------------------------------------------------------------------------
//
TInt CCsdFax::MapStatus( TInt& aStatus ) const
    {
    switch( aStatus )
        {
        case RMobileCall::EStatusUnknown:
            return KErrUnknown;

        case RMobileCall::EStatusIdle:
            aStatus = KConnectionUninitialised;
            break;

        case RMobileCall::EStatusDialling:
            aStatus = KCsdStartingDialling;
            break;

        case RMobileCall::EStatusRinging:
            return KErrUnknown;

        case RMobileCall::EStatusAnswering:
            aStatus = KCsdStartingAnswer;
            break;

        case RMobileCall::EStatusConnecting:
            aStatus = KCsdStartingConnect;
            break;

        case RMobileCall::EStatusConnected:
            aStatus = KCsdConnectionOpen;
            break;

         case RMobileCall::EStatusDisconnecting:
         case RMobileCall::EStatusDisconnectingWithInband:
            aStatus = KCsdStartingHangUp;
            break;

        default:
            return KErrUnknown;
        }

    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CCsdFax::GetTelNumber
// -----------------------------------------------------------------------------
//
TInt CCsdFax::GetTelNumber( TDes& aNumber ) const
    {
    LOGENTRFN("CCsdFax::GetTelNumber()")
    TInt err( KErrNone );

    if ( iState < ECallOpen )
        {
        err = KErrNotFound;
        }
    else
        {
        RMobileCall::TMobileCallInfoV1 info;
        RMobileCall::TMobileCallInfoV1Pckg infoPckg( info );
        err = iCall.GetMobileCallInfo( infoPckg );

        if ( KErrNone == err )
            {
            if ( infoPckg().iRemoteParty.iRemoteNumber.iTelNumber.Length() > 0 )
                {
                aNumber = infoPckg().iRemoteParty.iRemoteNumber.iTelNumber;
                }
            else if ( infoPckg().iDialledParty.iTelNumber.Length() > 0 )
                {
                aNumber = infoPckg().iDialledParty.iTelNumber;
                }
            }
        }

    LOGEXITFN1("CCsdFax::GetTelNumber()", err)
    return err;
    }

// -----------------------------------------------------------------------------
// CCsdFax::GetStartTime
// -----------------------------------------------------------------------------
//
TInt CCsdFax::GetStartTime( TTime& aTime ) const
    {
    TInt ret( KErrNone );

    if ( iState < ECallOpen )
        {
        return KErrNotFound;
        }

    TTimeIntervalSeconds duration;
    ret = iCall.GetCallDuration( duration );

    if ( KErrNone == ret )
        {
        TTime current;
        current.UniversalTime();
        aTime = current - duration;
        }
    return ret;
    }

// -----------------------------------------------------------------------------
// CCsdFax::Stop
// -----------------------------------------------------------------------------
//
TInt CCsdFax::Stop()
    {
    TInt err( KErrNone );

    if ( iState != ECallOpen )
        {
        return KErrNotFound;
        }

    err = iCall.HangUp();

    // Remove from server tables if
    // status notifier is not active.
    if ( !iStatusNotifier->IsActive() )
        {
        RemoveFromServer();
        }

    return err;
    }

// -----------------------------------------------------------------------------
// CCsdFax::RemoveFromServer
// -----------------------------------------------------------------------------
//
void CCsdFax::RemoveFromServer()
    {
    // Remove the connection from internal table
    TInt bearer( 0 );
    TBearerInfo bearerInfo( EBearerInfoCSD, ETrue);

    TConnInfo connInfo( 0, 0, 0, EBearerExternalCSD, bearerInfo );

    TInt err = GetBearer( bearer, bearerInfo );

    if ( KErrNone == err )
        {
        connInfo.iBearer = bearer;
        connInfo.iBearerInfo.iBearer = bearerInfo.iBearer;
        connInfo.iBearerInfo.iInternal = bearerInfo.iInternal;
        }

    iServer->Iap()->RemoveConnection( connInfo );
    }


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

// -----------------------------------------------------------------------------
// CCsdFaxUpNotifier::CCsdFaxUpNotifier
// -----------------------------------------------------------------------------
//
CCsdFaxUpNotifier::CCsdFaxUpNotifier(
        CCsdFax* aFaxModule,
        CConnMonServer* aServer,
        RMobilePhone* aMobilePhone,
        RLine& aLine)
        :
        CActive( EConnMonPriorityNormal ),
        iFaxModule( aFaxModule ),
        iServer( aServer ),
        iMobilePhone( aMobilePhone ),
        iLine( aLine )
    {
    }

// -----------------------------------------------------------------------------
// CCsdFaxUpNotifier::Construct
// -----------------------------------------------------------------------------
//
void CCsdFaxUpNotifier::Construct()
    {
    CActiveScheduler::Add( this );
    }

// Destructor
CCsdFaxUpNotifier::~CCsdFaxUpNotifier()
    {
    Cancel();
    }

// -----------------------------------------------------------------------------
// CCsdFaxUpNotifier::Receive
// Requests a new event (connection up/down) from RConnection
// -----------------------------------------------------------------------------
//
void CCsdFaxUpNotifier::Receive()
    {
    if ( IsActive() )
        {
        Cancel();
        }

    iName.FillZ();

    iLine.NotifyCallAdded( iStatus, iName );
    SetActive();
    }

// -----------------------------------------------------------------------------
// CCsdFaxUpNotifier::DoCancel
// Cancels the request from RConnection.
// -----------------------------------------------------------------------------
//
void CCsdFaxUpNotifier::DoCancel()
    {
    if ( IsActive() )
        {
        iLine.NotifyCallAddedCancel();
        }
    }

// -----------------------------------------------------------------------------
// CCsdFaxUpNotifier::RunL
// Handles the event that has arrived from RConnection
// -----------------------------------------------------------------------------
//
void CCsdFaxUpNotifier::RunL()
    {
    // All RunL():s outside CServer-derived main class MUST NOT LEAVE.
    // Use TRAPD when needed.

    if ( iStatus.Int() != KErrNone )
        {
        LOGIT1("External Csd up event FAILED <%d>", iStatus.Int() )
        }
    else
        {
        RMmCustomAPI customApi;
        RMmCustomAPI::TCallOrigin origin( RMmCustomAPI::EUnknown );

        TInt ret = customApi.Open( *iMobilePhone );

        if ( KErrNone == ret )
            {
            customApi.CallOrigin( iName, origin );
            customApi.Close();
            }

        if ( origin == RMmCustomAPI::EOutsider )
            {
            TInt bearer( 0 );
            TBearerInfo bearerInfo;
            TInt err( KErrNone );

            LOGIT("SERVER: EVENT -> new EXTERNAL CSD connection")

            if ( iFaxModule->IsValid() )
                {
                // Sometimes when data call is rejected by the other end, a new
                // data call is started before the old one has been notified to
                // be closed. In this case send the EConnMonDeleteConnection to
                // all clients that are listening.
                iEventInfo.Reset();
                iEventInfo.iEventType = EConnMonDeleteConnection;
                iEventInfo.iConnectionId = iFaxModule->ConnectionId();

                iServer->EventQueue()->Add( iEventInfo );

                // Remove from server tables
                iFaxModule->RemoveFromServer();

                // Close the call
                iFaxModule->CloseCall();

                LOGIT("SERVER: Closed the unfinished EXTERNAL CSD connection")
                }

            err = iFaxModule->OpenCall( iName );

            if ( KErrNone == err )
                {
                err = iFaxModule->GetBearer( bearer, bearerInfo );
                }

            if ( KErrNone == err )
                {
                // Send event to clients
                TConnInfo connInfo( 0, 0, 0, bearer, bearerInfo );

                iEventInfo.Reset();

                iEventInfo.iEventType = EConnMonCreateConnection;

                // Add to the connection table and fill in the new connectioId to connInfo
                TRAP( ret, ( err = iServer->Iap()->AddConnectionL( connInfo ) ) );

                if ( ret )
                    {
                    LOGIT("AddConnectionL failed.")
                    return; // Can't leave
                    }

                // Set connection id
                iEventInfo.iConnectionId = connInfo.iConnectionId;
                iFaxModule->SetConnectionId( connInfo.iConnectionId );

                // Send event to all clients that are listening
                iServer->EventQueue()->Add( iEventInfo );
                }
            else
                {
                LOGIT("Could not get the external call info!")
                }
            }

        // New request
        Receive();
        }
    }

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

// -----------------------------------------------------------------------------
// CCsdStatusNotifier::CCsdStatusNotifier
// -----------------------------------------------------------------------------
//
CCsdStatusNotifier::CCsdStatusNotifier(
        CCsdFax* aFaxModule,
        CConnMonServer* aServer )
        :
        CActive( EConnMonPriorityNormal ),
        iFaxModule( aFaxModule ),
        iServer( aServer )
    {
    }

// -----------------------------------------------------------------------------
// CCsdStatusNotifier::Construct
// -----------------------------------------------------------------------------
//
void CCsdStatusNotifier::Construct()
    {
    CActiveScheduler::Add( this );
    }

// Destructor
CCsdStatusNotifier::~CCsdStatusNotifier()
    {
    Cancel();
    }

// -----------------------------------------------------------------------------
// CCsdStatusNotifier::Start
// Requests a new event (connection up/down) from RConnection
// -----------------------------------------------------------------------------
//
void CCsdStatusNotifier::Start( RMobileCall* aCall )
    {
    // Cancel must be called before assigning a new aCall handle
    if ( IsActive() )
        {
        Cancel();
        }

    iCall = aCall;
    Receive();
    }

// -----------------------------------------------------------------------------
// CCsdStatusNotifier::Receive
// Requests a new event (connection up/down) from RConnection
// -----------------------------------------------------------------------------
//
void CCsdStatusNotifier::Receive()
    {
    if ( IsActive() )
        {
        Cancel();
        }

    iCall->NotifyMobileCallStatusChange( iStatus, iMobileCallStatus );
    SetActive();
    }

// -----------------------------------------------------------------------------
// CCsdStatusNotifier::DoCancel
// Cancels the request from RConnection.
// -----------------------------------------------------------------------------
//
void CCsdStatusNotifier::DoCancel()
    {
    if ( IsActive() )
        {
        iCall->CancelAsyncRequest( EMobileCallNotifyMobileCallStatusChange );
        }
    }

// -----------------------------------------------------------------------------
// CCsdStatusNotifier::RunL
// Handles the event that has arrived from RConnection
// -----------------------------------------------------------------------------
//
void CCsdStatusNotifier::RunL()
    {
    // All RunL():s outside CServer-derived main class MUST NOT LEAVE.
    // Use TRAPD when needed.

    if ( iStatus.Int() != KErrNone )
        {
        LOGIT1("External Csd status FAILED <%d>", iStatus.Int() )
        }
    else
        {
        // Send event to clients
        LOGIT1("SERVER: EVENT -> EXTERNAL CSD status changed <%d>", iMobileCallStatus )

        iEventInfo.Reset();
        iEventInfo.iEventType = EConnMonConnectionStatusChange;

        iEventInfo.iConnectionId = iFaxModule->ConnectionId();

        TInt status = iMobileCallStatus;
        TInt err = iFaxModule->MapStatus( status );
        iEventInfo.iData = status;

        if ( ( iServer->NumberOfListeners() > 0 ) && ( err == KErrNone ) )
            {
            // Send event to all clients that are listening
            iServer->EventQueue()->Add( iEventInfo );
            }

        if ( ( iMobileCallStatus == ( TInt )RMobileCall::EStatusDisconnecting )
              ||
             ( iMobileCallStatus == ( TInt )RMobileCall::EStatusDisconnectingWithInband ) )
            {
            // Send connection closed event to all clients that are listening
            iEventInfo.Reset();
            iEventInfo.iEventType = EConnMonDeleteConnection;
            iEventInfo.iConnectionId = iFaxModule->ConnectionId();

            iServer->EventQueue()->Add( iEventInfo );

            // Remove from server tables
            iFaxModule->RemoveFromServer();

            // Close the call
            iFaxModule->CloseCall();

            // Stop listening
            return;
            }

        // New request
        Receive();
        }
    }

// End-of-file