/*
* Copyright (c) 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:  ECOM plugin for communication over IP port
*
*/


// INCLUDE FILES
#include "HtiIPCommEcomPlugin.h"
#include "HtiConnectionManager.h"
#include "HtiCfg.h"
#include "HtiIPCommlogging.h"

#include <commdb.h>             // CCommsDatabase
#include <hticfg.h>


// CONSTANTS
const static TInt KMaxHtiNotifierLength = 128;

_LIT( KHtiIPCommError, "HtiIpCommError" );
_LIT( KHtiOkButton, "OK" );

_LIT( KHtiCfgPath,      "\\" ); // root of drive
_LIT( KHtiIPCommCfg,    "HTIIPComm.cfg" );
_LIT8( KIAPId,          "IAPId" );
_LIT8( KIAPName,        "IAPName" );
_LIT8( KLocalPort,      "LocalPort" );
_LIT8( KRemoteHost,     "RemoteHost" );
_LIT8( KRemotePort,     "RemotePort" );
_LIT8( KConnectTimeout, "ConnectTimeout" );


void LogLocalHost( RSocket& aSocket )
    {
#ifdef __ENABLE_LOGGING__
    // print the local ip to log
    HTI_LOG_TEXT( "LocalHost:" );
    TBuf<0x20> tmp;
    TInetAddr localHost;
    aSocket.LocalName( localHost );
    localHost.Output( tmp );
    tmp.AppendFormat( _L(":%d"), localHost.Port() );
    HTI_LOG_DES( tmp );
#else
    aSocket.LocalPort();  // avoid compiler warning
#endif
    }

void LogRemoteHost( RSocket& aSocket )
    {
#ifdef __ENABLE_LOGGING__
    // print the local ip to log
    HTI_LOG_TEXT( "RemoteHost:" );
    TBuf<0x20> tmp;
    TInetAddr remoteHost;
    aSocket.RemoteName( remoteHost );
    remoteHost.Output( tmp );
    tmp.AppendFormat( _L(":%d"), remoteHost.Port() );
    HTI_LOG_DES( tmp );
#else
    aSocket.LocalPort();  // avoid compiler warning
#endif
    }


CHtiConnectionManager* CHtiConnectionManager::NewL( CHtiIPCommServer* aServer )
    {
    HTI_LOG_FUNC_IN( "CHtiConnectionManager::NewL" );
    CHtiConnectionManager* self = new (ELeave) CHtiConnectionManager( aServer );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    HTI_LOG_FUNC_OUT( "CHtiConnectionManager::NewL" );
    return self;
    }

CHtiConnectionManager::CHtiConnectionManager( CHtiIPCommServer* aServer ):
    CActive( EPriorityStandard ),
    iServer( aServer ),
    iCfg( NULL ),
    iListenPort( 0 ),
    iState( EDisconnected ),
    iReceiveRequestComplete( ETrue ),
    iSendRequestComplete( ETrue ),
    iSendMonitor( NULL ),
    iReceiveMonitor( NULL ),
    iConnectTimer( NULL )
    {
    iReceiveBuffer.Zero();
    iSendBuffer.Zero();
    CActiveScheduler::Add(this);
    }

CHtiConnectionManager::~CHtiConnectionManager()
    {
    HTI_LOG_FUNC_IN( "CHtiConnectionManager::~CHtiConnectionManager" );

    if ( iCfg )
        delete iCfg;

    if ( iConnectTimer )
        delete iConnectTimer;

    if ( iDataSocket.SubSessionHandle() )
        iDataSocket.Close();

    if ( iListenSocket.SubSessionHandle() )
        iListenSocket.Close();

    if ( iSendMonitor )
        delete iSendMonitor;

    if ( iReceiveMonitor )
        delete iReceiveMonitor;

    if ( iConnection.SubSessionHandle() )
        iConnection.Close();

    if ( iSocketServ.Handle() )
        iSocketServ.Close();

    // NOTE: If this is done in the beginning the server will never die!
    Cancel();

    HTI_LOG_FUNC_OUT( "CHtiConnectionManager::~CHtiConnectionManager" );
    }


void CHtiConnectionManager::ConstructL()
    {
    HTI_LOG_FUNC_IN( "CHtiConnectionManager::ConstructL" );

    // Load configuration file
    iCfg = CHtiCfg::NewL();
    TRAPD( err, iCfg->LoadCfgL( KHtiCfgPath, KHtiIPCommCfg ) );
    if ( err )
        {
        HTI_LOG_FORMAT( "LoadCfgL err %d", err );
        ShowErrorNotifierL( _L( "Could not load config file" ), err );
        User::Leave( err );
        }

    // Get IAP
    ReadIAPConfigL();

    // Create monitors and timers
    iSendMonitor    = CHtiSocketMonitor::NewL( MHtiSocketObserver::EWriteSocket, this);
    iReceiveMonitor = CHtiSocketMonitor::NewL( MHtiSocketObserver::EReadSocket, this);
    iConnectTimer   = CHtiTimer::NewL( *this );

    // Open socket server
    err = iSocketServ.Connect();
    if ( err )
        {
        HTI_LOG_FORMAT( "error connecting to socket server %d", err);
        User::Leave( err );
        }

/*
    HTI_LOG_TEXT( "Supported protocols:" );
    TUint numOfProtocols;
    iSocketServ.NumProtocols( numOfProtocols );
    for ( TInt i = 1; i <= numOfProtocols; i++ )
        {
        TProtocolDesc desc;
        iSocketServ.GetProtocolInfo( i, desc  );
        HTI_LOG_DES( desc.iName );
        HTI_LOG_FORMAT( "AddrFamily : %d", desc.iAddrFamily );
        HTI_LOG_FORMAT( "SockType   : %d", desc.iSockType );
        HTI_LOG_FORMAT( "Protocol   : %d", desc.iProtocol );
        }
*/

    // Start IAP
    err = iConnection.Open( iSocketServ );
    if ( err )
        {
        HTI_LOG_FORMAT( "error opening connection %d", err);
        User::Leave( err );
        }

    HTI_LOG_TEXT( "Starting IAP" );
    iConnPref.SetDialogPreference( ECommDbDialogPrefDoNotPrompt );
    iConnPref.SetIapId( iIAPId );
    iConnection.Start( iConnPref, iStatus );
    iState = EStartingIAP;
    SetActive();

    HTI_LOG_FUNC_IN( "CHtiConnectionManager::ConstructL" );
    }


void CHtiConnectionManager::ReadIAPConfigL()
    {
    // Try to read IAP id first
    TRAPD( err, iIAPId = iCfg->GetParameterIntL( KIAPId ) );
    if ( err == KErrNone )
        {
        HTI_LOG_FORMAT( "Using IAP id %d", iIAPId);
        }
    else
        {
        // IAP id not defined try reading IAP name
        TBuf8<KMaxParameterValueLength> IAPNameCfg;
        TRAP( err, IAPNameCfg = iCfg->GetParameterL( KIAPName ) );

        // If IAP name is not defined it wont be found from commsdb...

        HTI_LOG_TEXT( "Searching for IAP:" );
        HTI_LOG_DES( IAPNameCfg );

        // open commdb
        CCommsDatabase* commDb = CCommsDatabase::NewL( EDatabaseTypeIAP );
        CleanupStack::PushL(commDb);

        // open IAP table

        // Using all bearers from TCommDbBearer because when
        // using KCommDbBearerUnknown it just leaves
        TUint32 bearerSet = KCommDbBearerCSD|KCommDbBearerPSD|KCommDbBearerLAN|
                            KCommDbBearerVirtual|KCommDbBearerPAN|
                            KCommDbBearerWLAN;

        CCommsDbTableView* commView =
            commDb->OpenIAPTableViewMatchingBearerSetLC(bearerSet,
                                                        ECommDbConnectionDirectionUnknown);

        // search all IAPs
        HTI_LOG_TEXT( "IAP records:" );
        if (commView->GotoFirstRecord() == KErrNone)
            {
            do
                {
                TBuf8<KCommsDbSvrMaxFieldLength> iapName;
                commView->ReadTextL( TPtrC(COMMDB_NAME), iapName );
                HTI_LOG_DES( iapName );

                if ( iapName == IAPNameCfg )
                    {
                    commView->ReadUintL( TPtrC(COMMDB_ID), iIAPId );
                    HTI_LOG_FORMAT( "Found it! IAP id %d", iIAPId );
                    }

                }
            while ( commView->GotoNextRecord() == KErrNone );
            }
        CleanupStack::PopAndDestroy(2); // commView, commDb
        }

    // Cannot start if Internet Access Point is not defined
    if ( iIAPId == 0 )
        {
        HTI_LOG_TEXT( "IAP not defined" );
        ShowErrorNotifierL( _L( "IAP not defined" ), KErrNotFound );
        User::Leave( KErrNotFound );
        }
    }


void CHtiConnectionManager::ReadConnectionConfigL()
    {
    // Read listening port number from config file
    TRAPD( err, iListenPort = iCfg->GetParameterIntL( KLocalPort ) );

    if ( iListenPort == 0)
        {
        // ...or remote host to connect

        TBuf8<KMaxParameterValueLength> remoteHostCfg;
        TRAP( err, remoteHostCfg = iCfg->GetParameterL( KRemoteHost ) );
        if ( err )
            {
            HTI_LOG_TEXT( "No remote host specified!" )
            ShowErrorNotifierL( _L( "No remote host specified!" ), err );
            User::Leave( err );
            }

        // Convert TDesC8 -> TDesC
        TBuf<KMaxParameterValueLength> tmp;
        tmp.Copy( remoteHostCfg );

        // Check remote host if its a plain ip address
        if ( iRemoteHost.Input( tmp ) )
            {
            // ...its not. Do a DNS-lookup request
            HTI_LOG_TEXT( "Do a DSN-lookup request" );

            RHostResolver resolver;
            err = resolver.Open( iSocketServ, KAfInet, KProtocolInetUdp, iConnection );
            if ( err )
                {
                HTI_LOG_FORMAT( "error opening resolver %d", err );
                User::Leave( err );
                }

            TNameEntry entry;
            err = resolver.GetByName( tmp, entry );
            if ( err )
                {
                HTI_LOG_FORMAT( "error getting address by name %d", err );
                ShowErrorNotifierL(
                    _L( "Could not resolve remote host!" ), err );
                User::Leave( err );
                }

            iRemoteHost = entry().iAddr;

            resolver.Close();
            }

        // Get remote host port
        TRAP( err, iRemoteHost.SetPort( iCfg->GetParameterIntL( KRemotePort ) ) );
        if ( err )
            {
            HTI_LOG_TEXT( "No remote port specified!" )
            ShowErrorNotifierL( _L( "No remote port specified!" ), err );
            User::Leave( err );
            }

        // Get connect timeout
        TRAP( err, iConnectTimeout = iCfg->GetParameterIntL( KConnectTimeout ) );
        if ( err )
            {
            // default is 30 seconds
            iConnectTimeout = 30;
            }

        HTI_LOG_FORMAT( "Connect timeout %d", iConnectTimeout );
        }
    }

void CHtiConnectionManager::StartConnectingL()
    {
    HTI_LOG_FUNC_IN( "CHtiConnectionManager::StartConnectingL" );
    CancelAllRequests();

    // close if open
    if ( iDataSocket.SubSessionHandle() )
        iDataSocket.Close();

    // open data socket
    TInt err = iDataSocket.Open( iSocketServ,
                        KAfInet,
                        KSockStream,
                        KProtocolInetTcp,
                        iConnection );
    if ( err )
        {
        HTI_LOG_FORMAT( "error opening data socket %d", err );
        User::Leave( err );
        }

    iDataSocket.Connect( iRemoteHost, iStatus );
    iState = EConnecting;

    // Set a timeout for this operation if timer is not
    // already active and there is a timeout defined
    if ( iConnectTimeout && !iConnectTimer->IsActive() )
        {
        // iConnectTimeout is in seconds
        iConnectTimer->After( iConnectTimeout*1000000 );
        }

    SetActive();
    HTI_LOG_FUNC_OUT( "CHtiConnectionManager::StartConnectingL" );
    }


void CHtiConnectionManager::StartListeningL()
    {
    HTI_LOG_FUNC_IN( "CHtiConnectionManager::StartListeningL" );
    HTI_LOG_FORMAT( "Port %d", iListenPort );

    CancelAllRequests();

    // close if open
    if ( iDataSocket.SubSessionHandle() )
        iDataSocket.Close();

    // open empty socket
    TInt err = iDataSocket.Open( iSocketServ  );
    if ( err )
        {
        HTI_LOG_FORMAT( "error opening blank socket %d", err );
        User::Leave( err );
        }

    // start listening
    iListenSocket.Accept( iDataSocket, iStatus );
    iState = EWaitingConnection;

    SetActive();
    HTI_LOG_FUNC_OUT( "CHtiConnectionManager::StartListeningL" );
    }

void CHtiConnectionManager::CancelAllRequests()
    {
    HTI_LOG_TEXT( "Cancelling all active server requests" );
    CancelReceive();
    CancelSend();
    }

void CHtiConnectionManager::RunL()
    {
    HTI_LOG_FUNC_IN( "CHtiConnectionManager::RunL" );
    HTI_LOG_FORMAT( "status %d", iStatus.Int() );

    TInt err;

    switch ( iState )
        {
        case EStartingIAP:

            HTI_LOG_TEXT( "EStartingIAP" );

            if ( iStatus.Int() )
                {
                HTI_LOG_FORMAT( "error starting IAP %d", iStatus.Int() );
                ShowErrorNotifierL( _L( "Error starting IAP" ), iStatus.Int() );
                User::Leave( iStatus.Int() );
                }

            ReadConnectionConfigL();

            // remote host is defined - start connecting to it
            if ( iListenPort == 0 )
                {
                StartConnectingL();
                }
            // remote host not defined - start listening
            else
                {
                HTI_LOG_TEXT( "Setting up listen socket" );

                // open listening socket
                err = iListenSocket.Open( iSocketServ,
                                    KAfInet,
                                    KSockStream,
                                    KProtocolInetTcp,
                                    iConnection );
                if ( err )
                    {
                    HTI_LOG_FORMAT( "error opening listen socket %d", err );
                    User::Leave( err );
                    }

                // set the port to listen
                err = iListenSocket.SetLocalPort( iListenPort );
                if ( err )
                    {
                    HTI_LOG_FORMAT( "error setting local port %d", err );
                    User::Leave( err );
                    }

                // set listen queue size
                err = iListenSocket.Listen( 5 );
                if ( err )
                    {
                    HTI_LOG_FORMAT( "error settig up listening socket %d", err );
                    User::Leave( err );
                    }

                StartListeningL();
                }


            break;

        case EWaitingConnection:
            HTI_LOG_TEXT( "EWaitingConnection" );

            if ( iStatus.Int() )
                {
                HTI_LOG_FORMAT( "error accepting connection %d", iStatus.Int() );
                ShowErrorNotifierL(
                    _L( "Error accepting connection!" ), iStatus.Int() );
                User::Leave( iStatus.Int() );
                }

            iState = EConnected;
            HTI_LOG_TEXT( "Connected!" );
            User::InfoPrint( _L("HtiIPComm: connected!") );

            if ( !iReceiveRequestComplete )
                {
                // There is a pending read request
                HTI_LOG_TEXT( "Pending read request" );
                ReadSocket();
                }

            if ( !iSendRequestComplete )
                {
                // There is a pending write request
                HTI_LOG_TEXT( "Pending write request" );
                WriteSocket();
                }

            break;

        case EConnecting:
            HTI_LOG_TEXT( "EConnecting" );

            if ( iStatus.Int() )
                {
                HTI_LOG_FORMAT( "error connecting to remote host %d", iStatus.Int() );
                HTI_LOG_TEXT( "trying again..." );
                User::After( 1000000 ); // wait 1 second before trying again
                StartConnectingL();
                }
            else
                {
                // Cancel the timer
                iConnectTimer->Cancel();

                iState = EConnected;
                HTI_LOG_TEXT( "Connected!" );
                User::InfoPrint( _L("HtiIPComm: connected!") );

                //LogLocalHost( iDataSocket );
                //LogRemoteHost( iDataSocket );

                if ( !iReceiveRequestComplete )
                    {
                    // There is a pending read request
                    HTI_LOG_TEXT( "Pending read request" );
                    ReadSocket();
                    }

                if ( !iSendRequestComplete )
                    {
                    // There is a pending write request
                    HTI_LOG_TEXT( "Pending write request" );
                    WriteSocket();
                    }
                }

            break;

        case EConnected:
            HTI_LOG_TEXT( "EConnected" );
            break;

        case EDisconnecting:
            HTI_LOG_TEXT( "EDisconnecting" );
            break;

        case EDisconnected:
            HTI_LOG_TEXT( "EDisconnected" );
            break;

        default:
            HTI_LOG_TEXT( "Unknown" );
            User::Panic( _L("HtiIPComm"), EUnknownState );
        }

    HTI_LOG_FUNC_OUT( "CHtiConnectionManager::RunL" );
    }


void CHtiConnectionManager::DoCancel()
    {
    HTI_LOG_TEXT( "CHtiConnectionManager::DoCancel" );
    }


TInt CHtiConnectionManager::RunError(TInt aError)
    {
    HTI_LOG_FUNC_IN( "CHtiConnectionManager::RunError" );
    HTI_LOG_FORMAT( "error %d closing server...", aError );
    iServer->CloseServer();
    HTI_LOG_FUNC_OUT( "CHtiConnectionManager::RunError" );
    aError = aError;
    return KErrNone;
    }


void CHtiConnectionManager::Receive( const RMessage2& aMessage )//( TDes8& aRawdataBuf, TRequestStatus& aStatus )
    {
    HTI_LOG_FUNC_IN( "CHtiConnectionManager::Receive" );

    if ( !iReceiveRequestComplete )
        {
        HTI_LOG_TEXT( "complete with KErrServerBusy" );
        aMessage.Complete( KErrServerBusy );
        }
    else
        {
        iReceiveRequestComplete = EFalse;
        iReceiveRequest = aMessage;

        if ( iState == EConnected )
            {
            ReadSocket();
            }
        else
            {
            HTI_LOG_TEXT( "not connected" );
            }
        }

    HTI_LOG_FUNC_OUT( "CHtiConnectionManager::Receive" );
    }


void CHtiConnectionManager::Send( const RMessage2& aMessage )
    {
    HTI_LOG_FUNC_IN( "CHtiConnectionManager::Send" );

    if ( !iSendRequestComplete )
        {
        HTI_LOG_TEXT( "complete with KErrServerBusy" );
        aMessage.Complete( KErrServerBusy );
        }
    else
        {
        iSendRequestComplete = EFalse;
        iSendRequest = aMessage;
        TInt err = aMessage.Read( 0, iSendBuffer );
        if ( err )
            {
            User::Panic( _L("HtiIPComm"), EBadDescriptor );
            }

        if ( iState == EConnected )
            {
            WriteSocket();
            }
        else
            {
            HTI_LOG_TEXT( "not connected" );
            }
        }

    HTI_LOG_FUNC_OUT( "CHtiConnectionManager::Send" );
    }

void CHtiConnectionManager::ReadSocket()
    {
    HTI_LOG_FUNC_IN( "CHtiConnectionManager::ReadSocket" );

    iReceiveMonitor->Activate();
    iReceiveBuffer.Zero();
    iDataSocket.RecvOneOrMore( iReceiveBuffer, 0,
        iReceiveMonitor->iStatus, iRecvLen );

    // This works fine with the emulator...
    //iDataSocket.RecvOneOrMore( *(TDes8*) iReceiveRequest.Ptr0(),
    //                       0, iReceiveMonitor->iStatus, iRecvLen );

    HTI_LOG_FUNC_OUT( "CHtiConnectionManager::ReadSocket" );
    }

void CHtiConnectionManager::WriteSocket()
    {
    HTI_LOG_FUNC_IN( "CHtiConnectionManager::WriteSocket" );

    iSendMonitor->Activate();
    iDataSocket.Write( iSendBuffer, iSendMonitor->iStatus );

    // This works fine with the emulator...
    //iDataSocket.Write( *(TDesC8*) iSendRequest.Ptr0(),
    //               iSendMonitor->iStatus );

    HTI_LOG_FUNC_OUT( "CHtiConnectionManager::WriteSocket" );
    }

void CHtiConnectionManager::CancelReceive()
    {
    HTI_LOG_TEXT( "CHtiConnectionManager::CancelReceive" );

    if ( !iReceiveRequestComplete )
        {
        // Is there an active socket receive?
        if ( iReceiveMonitor->IsActive() )
            {
            // ReportComplete() should complete this
            HTI_LOG_TEXT( "CancelRecv" );
            iDataSocket.CancelRecv();
            }
        else
            {
            HTI_LOG_TEXT( "complete with KErrCancel" );
            iReceiveRequest.Complete( KErrCancel );
            iReceiveRequestComplete = ETrue;
            iReceiveBuffer.Zero();
            }
        }
    }

void CHtiConnectionManager::CancelSend()
    {
    HTI_LOG_TEXT( "CHtiConnectionManager::CancelSend" );

    if ( !iSendRequestComplete )
        {
        // Is there an active socket send?
        if ( iSendMonitor->IsActive() )
            {
            // ReportComplete() should complete this
            HTI_LOG_TEXT( "CancelWrite" );
            iDataSocket.CancelWrite();
            }
        else
            {
            HTI_LOG_TEXT( "complete with KErrCancel" );
            iSendRequest.Complete( KErrCancel );
            iSendRequestComplete = ETrue;
            iSendBuffer.Zero();
            }
        }
    }

void CHtiConnectionManager::ReportComplete( MHtiSocketObserver::TRequestType aType, TInt aError )
    {
    HTI_LOG_FUNC_IN( "CHtiConnectionManager::ReportComplete" );

    HTI_LOG_FORMAT( "error %d", aError );

    TInt err = 0;

    switch ( aType )
        {
        case MHtiSocketObserver::EReadSocket:
            HTI_LOG_TEXT( "EReadSocket" );
            err = iReceiveRequest.Write( 0 , iReceiveBuffer );
            if ( err )
                {
                HTI_LOG_FORMAT( "Panic! Error writing received data to client buffer %d", err );
                User::Panic( _L("HtiIPComm"), EBadDescriptor );
                }

            iReceiveBuffer.Zero();
            iReceiveRequestComplete = ETrue;
            iReceiveRequest.Complete( aError );

            break;

        case MHtiSocketObserver::EWriteSocket:
            HTI_LOG_TEXT( "EWriteSocket" );
            iSendBuffer.Zero();
            iSendRequestComplete = ETrue;
            iSendRequest.Complete( aError );
            break;

        default:
            User::Panic( _L("HtiIPComm"), EUnknownCompletion );
        }


    // Disconnect if there is an error.
    if ( aError &&
        ( aError != KErrCancel ) ) // ...except when there is a cancel
        {
        iState = EDisconnected;
        HTI_LOG_TEXT( "Disconnected!" );
        User::InfoPrint( _L("HtiIPComm: Disconnected!") );

        // If disconnected try to listen or connect again
        if ( iListenPort == 0 )
            {
            // wait 1 second before trying again
            User::After( 1000000 );
            StartConnectingL();
            }
        else
            {
            StartListeningL();
            }
        }

    HTI_LOG_FUNC_OUT( "CHtiConnectionManager::ReportComplete" );
    }

CHtiTimer* CHtiTimer::NewL( MHtiTimerObserver& aObserver )
    {
    CHtiTimer* self = new (ELeave) CHtiTimer( aObserver );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

CHtiTimer::CHtiTimer( MHtiTimerObserver& aObserver ):
    CTimer( EPriorityUserInput ),
    iObserver( aObserver)
    {
    }

CHtiTimer::~CHtiTimer()
    {
    Cancel();
    }

void CHtiTimer::ConstructL()
    {
    CTimer::ConstructL();
    CActiveScheduler::Add( this );
    }

void CHtiTimer::RunL()
    {
    iObserver.TimerExpiredL();
    }

TInt CHtiTimer::RunError(TInt aError)
    {
    HTI_LOG_FORMAT( "CHtiTimer::RunError %d", aError );
    aError = aError;
    return KErrNone;
    }

void CHtiConnectionManager::TimerExpiredL()
    {
    HTI_LOG_TEXT( "Timed out! Closing IPCommServer..." );
    ShowErrorNotifierL(
        _L( "Timed out connecting to remote host!" ), KErrTimedOut );
    iServer->CloseServer();
    }

void CHtiConnectionManager::ShowErrorNotifierL( const TDesC& aText,
                                                   TInt aErr )
    {
    RNotifier notifier;
    User::LeaveIfError( notifier.Connect() );

    TBuf<KMaxHtiNotifierLength> errorMsg;
    // aText is cut if it's too long - leaving some space also for error code
    errorMsg.Append( aText.Left( errorMsg.MaxLength() - 10 ) );
    errorMsg.Append( _L("\n") );
    errorMsg.AppendNum( aErr );

    TRequestStatus status;
    TInt button;
    notifier.Notify( KHtiIPCommError, errorMsg,
                     KHtiOkButton, KNullDesC, button, status );
    User::WaitForRequest( status );
    notifier.Close();
    }



