atext/server/src/atextsession.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:38:54 +0100
branchRCL_3
changeset 24 e9b924a62a66
parent 23 5b153be919d4
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201031 Kit: 201035

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


#include <badesca.h>
#include <atextpluginbase.h>
#include <atext.h>
#include "atextsrv.h"
#include "atextclientsrv.h"
#include "atextsession.h"
#include "utils.h"
#include "debug.h"

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

// ---------------------------------------------------------------------------
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CATExtSession* CATExtSession::NewL( CATExtSrv& aServer,
                                    const TVersion& aVersion )
    {
    return new (ELeave) CATExtSession( aServer, aVersion );
    }

// ---------------------------------------------------------------------------
// Destructor.
// ---------------------------------------------------------------------------
//
CATExtSession::~CATExtSession()
    {
    TRACE_FUNC_ENTRY
    Destruct( EFalse );
    TRACE_FUNC_EXIT
    }

// ---------------------------------------------------------------------------
// Handles the servicing of client requests passed to the server
// ---------------------------------------------------------------------------
//
void CATExtSession::ServiceL( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( iVersion.iMajor==KServerMajorVersionNumber &&
         iVersion.iMinor==KServerMinorVersionNumber &&
         iVersion.iBuild==KServerBuildVersionNumber )
        {
        DoServiceL( aMessage );
        }
    else
        {
        aMessage.Complete( KErrNotSupported );
        }
    TRACE_FUNC_EXIT
    }

// ---------------------------------------------------------------------------
// Handles the servicing of client requests passed to the server
// ---------------------------------------------------------------------------
//
void CATExtSession::DoServiceL( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    switch ( aMessage.Function() )
        {
        case EATExtSetExtensionInterface:
            {
            TRAPD( retTrap, IpcSetInterfaceL(aMessage) );
            if ( retTrap != KErrNone )
                {
                aMessage.Complete( retTrap );
                }
            else if ( !iMetadata->SupportExists() )
                {
                aMessage.Complete( KErrNotFound );
                }
            else
                {
                aMessage.Complete( KErrNone );
                }
            break;
            }
        case EATExtSynchronousClose:
            {
            IpcSynchronousClose( aMessage );
            }
            break;
        case EATExtHandleCommand:
            {
            IpcHandleCommand( aMessage );
            break;
            }
        case EATExtCancelHandleCommand:
            {
            IpcCancelHandleCommand( aMessage );
            break;
            }
        case EATExtGetNextPartOfReply:
            {
            IpcGetNextPartOfReply( aMessage );
            break;
            }
        case EATExtNumberOfPlugins:
            {
            IpcNumberOfPlugins( aMessage );
            }
            break;
        case EATExtReceiveUnsolicitedResult:
            {
            IpcReceiveUnsolicitedResult( aMessage );
            break;
            }
        case EATExtCancelReceiveUnsolicitedResult:
            {
            IpcCancelReceiveUrc( aMessage );
            break;
            }
        case EATExtMarkUrcHandlingOwnership:
            {
            IpcMarkUrcHandlingOwnership( aMessage );
            break;
            }
        case EATExtReceiveEcomPluginChange:
            {
            IpcReceiveEcomPluginChange( aMessage );
            }
            break;
        case EATExtCancelReceiveEcomPluginChange:
            {
            IpcCancelReceiveEcomPluginChange( aMessage );
            }
            break;
        case EATExtReportQuietModeChange:
            {
            IpcReportQuietModeChange( aMessage );
            }
            break;
        case EATExtReportVerboseModeChange:
            {
            IpcReportVerboseModeChange( aMessage );
            }
            break;
        case EATExtReportCharacterChange:
            {
            IpcReportCharacterChange( aMessage );
            }
            break;
        case EATExtReportListenerUpdateReady:
            {
            IpcReportListenerUpdateReady( aMessage );
            }
            break;
        case EATExtBroadcastNvramStatusChange:
            {
            IpcBroadcastNvramStatusChange( aMessage );
            }
            break;
        case EATExtReportExternalHandleCommandError:
            {
            IpcReportExternalHandleCommandError( aMessage );
            }
            break;
        case EATExtReportHandleCommandAbort:
            {
            IpcReportHandleCommandAbort( aMessage );
            }
            break;
        case EATExtGetNextSpecialCommand:
            {
            IpcGetNextSpecialCommand( aMessage );
            }
            break;
        default:
            {
            aMessage.Complete( KErrNotSupported );
            break;
            }
        }
    TRACE_FUNC_EXIT
    }

// ---------------------------------------------------------------------------
// CATExtSession::CATExtSession
// ---------------------------------------------------------------------------
//
CATExtSession::CATExtSession( CATExtSrv& aServer, const TVersion& aVersion ) :
    iServer( aServer ),
    iEComSession( NULL ),
    iListener( NULL ),
    iMetadata( NULL ),
    iVersion( aVersion )
    {
    }

// ---------------------------------------------------------------------------
// Handles the servicing of setting up interface
// ---------------------------------------------------------------------------
//
void CATExtSession::IpcSetInterfaceL( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( iMetadata || iListener )
        {
        TRACE_FUNC_EXIT
        User::Leave( KErrGeneral );
        }
    iEComSession = &REComSession::OpenL();
    TPckgBuf<TUid> ifUidPckgBuf;
    TInt retTemp = ReadStructFromMessage( ifUidPckgBuf,
                                          EATExtConnectParamUid,
                                          aMessage );
    if ( retTemp != KErrNone )
        {
        TRACE_FUNC_EXIT
        User::Leave( retTemp );
        }
    RBuf8 connectionName;
    CleanupClosePushL( connectionName );
    retTemp = ReadStringFromMessage( connectionName,
                                     EATExtConnectParamName,
                                     aMessage );
    if ( retTemp != KErrNone )
        {
        TRACE_FUNC_EXIT
        User::Leave( retTemp );
        }
    // Create listener
    CATExtListen* listener = CATExtListen::NewLC( *iEComSession, this );
    listener->AddInterfaceUid( ifUidPckgBuf() );
    // Create metadata. Pass iListener to add the UIDs
    CATExtMetadata* metadata = CATExtMetadata::NewLC( *iEComSession,
                                                      listener,
                                                      *this );
    metadata->CreateImplementationMetadataL( ifUidPckgBuf(), connectionName );
    listener->IssueRequest();
    CleanupStack::Pop( metadata );
    CleanupStack::Pop( listener );
    CleanupStack::PopAndDestroy( &connectionName );
    iListener = listener;
    iMetadata = metadata;
    TRACE_FUNC_EXIT
    }

// ---------------------------------------------------------------------------
// Synchronously closes the session
// Optional: client can do either Close() or SynchronousClose()
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcSynchronousClose( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    Destruct( ETrue );
    aMessage.Complete( KErrNone );
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of AT commands
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcHandleCommand( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    if ( aMessage.GetDesMaxLength(EATExtHandleCmdParamReply) !=
         KDefaultCmdBufLength )
        {
        aMessage.Complete( KErrBadDescriptor );
        TRACE_FUNC_EXIT
        return KErrBadDescriptor;
        }
    TATExtCompletionInfo complInfo;
    complInfo.iProcessed = EFalse;
    complInfo.iReplyExpected = EFalse;
    TInt retTemp = iMetadata->HandleCommand( aMessage, complInfo );
    if ( retTemp != KErrNone )
        {
        TRACE_INFO(( _L8("Command handled with failure %d"), retTemp ));
        iMetadata->CompleteCommandMessage( NULL,
                                           retTemp,
                                           EFalse,               // no error reply
                                           EReplyTypeUndefined,  // general error condition
                                           EFalse );             // no multipart
        TRACE_FUNC_EXIT
        return retTemp;
        }
    // Next check the case without support: in this case a reply
    // can't be expected but return the "ERROR" anyway if needed.
    if ( !complInfo.iProcessed )
        {
        // Return "ERROR".
        TRACE_INFO(( _L8("Command handled without support: return \"ERROR\"") ));
        iMetadata->CompleteCommandMessage( NULL,
                                           KErrNone,
                                           ETrue,            // error reply
                                           EReplyTypeError,  // error type
                                           EFalse );         // no multipart
        TRACE_FUNC_EXIT
        return retTemp;
        }
    // Third, check a case where there is support but reply is not
    // expected. In this case "" must be returned to complete processing.
    // Note: The EFalse setting is used only for normal mode.
    if ( !complInfo.iReplyExpected )
        {
        // Return ""
        TRACE_INFO(( _L8("Command handled with support but no reply: return \"\"") ));
        iMetadata->CompleteCommandMessage( NULL,
                                           KErrNone,
                                           EFalse,           // no error reply
                                           EReplyTypeOther,  // reply type from plugin
                                           EFalse );         // no multipart
        TRACE_FUNC_EXIT
        return retTemp;
        }
    // The rest are for known command with reply or data in editor mode.
    // This case is handled in HandleCommand().
    TRACE_INFO(( _L8("Command handled: wait for asynchronous reply or do nothing") ));
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of pending AT command cancel
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcCancelHandleCommand( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TInt retVal = iMetadata->CancelHandleCommand();
    aMessage.Complete( retVal );
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of getting the next part of a reply for
// IpcHandleCommand().
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcGetNextPartOfReply( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TInt retTemp = iMetadata->GetNextPartOfReply( aMessage );
    if ( retTemp != KErrNone )
        {
        aMessage.Complete( retTemp );
        TRACE_FUNC_EXIT
        return retTemp;
        }
    // Note: Completed in metadata if successfull
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of number of plugins. This information is needed to
// instantiate one or more listeners by the user of the client.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcNumberOfPlugins( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TInt retVal = iMetadata->NumberOfPlugins();
    aMessage.Complete( retVal );
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of receiving unsolicited result codes. Note that
// IpcMarkUrcHandlingOwnership() must be called immediately after this in
// order for the message to receive their destination.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcReceiveUnsolicitedResult( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    if ( aMessage.GetDesMaxLength(EATExtReceiveUrcCmdParamBuf) !=
         KDefaultUrcBufLength )
        {
        aMessage.Complete( KErrBadDescriptor );
        TRACE_FUNC_EXIT
        return KErrBadDescriptor;
        }
    TPckgBuf<TUid> pluginUidPckgBuf;
    TInt retTemp = ReadStructFromMessage( pluginUidPckgBuf,
                                          EATExtReceiveUrcCmdParamUid,
                                          aMessage );
    if ( retTemp != KErrNone )
        {
        aMessage.Complete( retTemp );
        TRACE_FUNC_EXIT
        return retTemp;
        }
    TRAPD( retTrap, iMetadata->StartUrcReceivingL(aMessage,pluginUidPckgBuf()) );
    if ( retTrap != KErrNone )
        {
        aMessage.Complete( retTrap );
        TRACE_FUNC_EXIT
        return retTrap;
        }
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of pending receiving unsolicited result code cancel
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcCancelReceiveUrc( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TPckgBuf<TUid> pluginUidPckgBuf;
    TInt retTemp = ReadStructFromMessage( pluginUidPckgBuf,
                                          EATExtCancelReceiveUrcCmdParamUid,
                                          aMessage );
    if ( retTemp != KErrNone )
        {
        aMessage.Complete( retTemp );
        TRACE_FUNC_EXIT
        return retTemp;
        }
    TInt retVal = iMetadata->CancelUrcReceiving( pluginUidPckgBuf() );
    aMessage.Complete( retVal );
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of marking URC handling ownership. Call to this
// function must be done immediately after the call to
// IpcReceiveUnsolicitedResult().
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcMarkUrcHandlingOwnership( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TInt retVal = iMetadata->MarkUrcHandlingOwnership( aMessage );
    aMessage.Complete( retVal );
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of ECOM plugin change notifications
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcReceiveEcomPluginChange( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    if ( iEcomStatusMessage.Handle() )
        {
        aMessage.Complete( KErrBadHandle );
        TRACE_FUNC_EXIT
        return KErrBadHandle;
        }
    iEcomStatusMessage = aMessage;
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of pending ECOM plugin change notification cancel
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcCancelReceiveEcomPluginChange(
    const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    if ( !iEcomStatusMessage.Handle() )
        {
        aMessage.Complete( KErrBadHandle );
        TRACE_FUNC_EXIT
        return KErrBadHandle;
        }
    iEcomStatusMessage.Complete( KErrCancel );
    aMessage.Complete( KErrNone );
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of quiet mode change reporting. When quiet mode is on
// the behavior is the same as with AT command "ATQ1: Result code
// suppression". When quiet mode is on then verbose mode setting has no
// effect.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcReportQuietModeChange( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TPckgBuf<TBool> quietModePckgBuf;
    TInt retTemp = ReadStructFromMessage( quietModePckgBuf,
                                          EATExtReportQuietModeChangeParamMode,
                                          aMessage );
    if ( retTemp != KErrNone )
        {
        aMessage.Complete( retTemp );
        TRACE_FUNC_EXIT
        return retTemp;
        }
    iMetadata->SetQuietMode( quietModePckgBuf() );
    aMessage.Complete( KErrNone );
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of verbose mode change reporting. When verbose mode
// is on the behavior is the same as with AT command "ATV1: DCE Response
// format". If quiet mode is on then this setting has no effect.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcReportVerboseModeChange( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TPckgBuf<TBool> verboseModePckgBuf;
    TInt retTemp = ReadStructFromMessage( verboseModePckgBuf,
                                          EATExtReportVerboseModeChangeParamMode,
                                          aMessage );
    if ( retTemp != KErrNone )
        {
        aMessage.Complete( retTemp );
        TRACE_FUNC_EXIT
        return retTemp;
        }
    iMetadata->SetVerboseMode( verboseModePckgBuf() );
    aMessage.Complete( KErrNone );
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of character change reporting. The change to carriage
// return, line feed and backspace characters is reported to
// CATExtPluginBase's protected data so that the it can easily be used by the
// plugin implementation.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcReportCharacterChange( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TPckgBuf<TATExtensionCharType> charTypePckgBuf;
    TInt retTemp = ReadStructFromMessage( charTypePckgBuf,
                                          EATExtReportCharacterChangeParamType,
                                          aMessage );
    if ( retTemp != KErrNone )
        {
        aMessage.Complete( retTemp );
        TRACE_FUNC_EXIT
        return retTemp;
        }
    TPckgBuf<TInt8> charPckgBuf;
    retTemp = ReadStructFromMessage( charPckgBuf,
                                     EATExtReportCharacterChangeParamChar,
                                     aMessage );
    if ( retTemp != KErrNone )
        {
        aMessage.Complete( retTemp );
        TRACE_FUNC_EXIT
        return retTemp;
        }
    TInt retVal = iMetadata->SetCharacterValue( charTypePckgBuf(),
                                                charPckgBuf() );
    aMessage.Complete( retVal );
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of reporting listener update readiness. Client side
// listener has to use this after it has updates its own internal states after
// ECOM plugin change notification.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcReportListenerUpdateReady( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TPckgBuf<TUid> pluginUidPckgBuf;
    TInt retTemp = ReadStructFromMessage( pluginUidPckgBuf,
                                          EATExtReportListenerUpdateParamUid,
                                          aMessage );
    if ( retTemp != KErrNone )
        {
        aMessage.Complete( retTemp );
        TRACE_FUNC_EXIT
        return retTemp;
        }
    TPckgBuf<TATExtensionEcomType> updateTypePckgBuf;
    retTemp = ReadStructFromMessage( updateTypePckgBuf,
                                     EATExtReportListenerUpdateParamType,
                                     aMessage );
    if ( retTemp != KErrNone )
        {
        aMessage.Complete( retTemp );
        TRACE_FUNC_EXIT
        return retTemp;
        }
    TInt retVal = KErrNone;
    switch ( updateTypePckgBuf() )
        {
        case EEcomTypeUninstall:
            // 3. When client notifies of removal, remove the locked entry from metadata.
            // See also NotifyPluginUninstallation()
            retVal = iMetadata->RemoveImplementation( pluginUidPckgBuf() );
            break;
        case EEcomTypeInstall:
            // 4. When client notifies installation, remove the lock from metadata.
            // See also NotifyPluginInstallation()
            retVal = iMetadata->UnlockPluginAccess( pluginUidPckgBuf() );
            break;
        default:
            retVal = KErrNotSupported;
            break;
        }
    aMessage.Complete( retVal );
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of NVRAM status change broadcasting. The NVRAM status
// change is broadcasted to all of the plugins.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcBroadcastNvramStatusChange( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    RBuf8 nvramStatus;
    TInt retTemp = ReadStringFromMessage( nvramStatus,
                                          EATExtBroadcastNvramChangeParamNvram,
                                          aMessage );
    if ( retTemp != KErrNone )
        {
        aMessage.Complete( retTemp );
        nvramStatus.Close();
        TRACE_FUNC_EXIT
        return retTemp;
        }
    TInt retVal = iMetadata->BroadcastNvramStatusChange( nvramStatus );
    aMessage.Complete( retVal );
    nvramStatus.Close();
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of reporting about external handle command error
// condition.
// This is for cases when for example DUN decided the reply contained an
// error condition but the plugin is still handling the command internally.
// Example: "AT+TEST;+TEST2" was given in command line; "AT+TEST" returns
// non-EReplyTypeError condition and "AT+TEST2" returns EReplyTypeError.
// As the plugin(s) returning the non-EReplyTypeError may still have some
// ongoing operation then these plugins are notified about the external
// EReplyTypeError in command line processing. It is to be noted that
// HandleCommandCancel() is not sufficient to stop the processing as the
// command handling has already finished.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcReportExternalHandleCommandError(
    const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TInt retVal = iMetadata->ReportExternalHandleCommandError();
    aMessage.Complete( retVal );
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of reporting about abort condition in command
// handling.
// This is for cases when for example DUN decided an abort condition was
// received from DTE (ITU-T V.250 5.6.1). This API is for notifying the
// plugin that abort was requested. However the plugin currently handling
// the command may ignore the request if it doesn't support abort for the
// command or it may return the changed condition with
// HandleCommandCompleted()
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcReportHandleCommandAbort( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TInt retVal = iMetadata->ReportHandleCommandAbort( aMessage );
    aMessage.Complete( retVal );
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// Handles the servicing of getting the next special command RSS file entry.
// These commands are commands with a matching start but with any ending
// sequence. Command "ATD*99***1#" is one of these and the number of these
// commands should be kept minimal.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::IpcGetNextSpecialCommand( const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        aMessage.Complete( KErrGeneral );
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TPckgBuf<TBool> firstSearchPckgBuf;
    TInt retTemp = ReadStructFromMessage( firstSearchPckgBuf,
                                          EATExtGetNextSpecialCmdParamFirst,
                                          aMessage );
    if ( retTemp != KErrNone )
        {
        aMessage.Complete( retTemp );
        TRACE_FUNC_EXIT
        return retTemp;
        }
    TInt retVal = iMetadata->GetNextSpecialCommand( aMessage,
                                                    firstSearchPckgBuf() );
    aMessage.Complete( retVal );
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// Reads a string from a message
// ---------------------------------------------------------------------------
//
TInt CATExtSession::ReadStringFromMessage( RBuf8& aBuffer,
                                           TInt aDataSlot,
                                           const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    TInt retVal = KErrNone;
    TInt desLength = aMessage.GetDesLength( aDataSlot );
    if ( desLength <= 0 )
        {
        TRACE_FUNC_EXIT
        return KErrArgument;
        }
    retVal = aBuffer.Create( desLength );
    if ( retVal == KErrNone )
        {
        retVal = aMessage.Read( aDataSlot, aBuffer );
        TRACE_INFO(( _L("Read returned %d"), retVal ));
        }
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// Reads a struct from a message
// ---------------------------------------------------------------------------
//
TInt CATExtSession::ReadStructFromMessage( TDes8& aBuffer,
                                           TInt aDataSlot,
                                           const RMessage2& aMessage )
    {
    TRACE_FUNC_ENTRY
    TInt retVal = KErrNone;
    TInt desLength = aMessage.GetDesLength( aDataSlot );
    if ( desLength <= 0 )
        {
        TRACE_FUNC_EXIT
        return KErrArgument;
        }
    retVal = aMessage.Read( aDataSlot, aBuffer );
    TRACE_INFO(( _L("Read returned %d"), retVal ));
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// Destructs objects/associations for the current session
// ---------------------------------------------------------------------------
//
void CATExtSession::Destruct( TBool aSyncClose )
    {
    TRACE_FUNC_ENTRY
    if ( iEcomStatusMessage.Handle() )
        {
        iEcomStatusMessage.Complete( KErrServerTerminated );
        }
    delete iListener;
    iListener = NULL;
    delete iMetadata;
    iMetadata = NULL;
    if ( iEComSession )
        {
        iEComSession->Close();
        iEComSession = NULL; 
        }
    if ( !aSyncClose )
        {
        REComSession::FinalClose();
        iServer.ClientClosed( *this );
        }
    TRACE_FUNC_EXIT
    }

// ---------------------------------------------------------------------------
// From MATExtPluginObserver.
// Called by extension plugins when there is an unsolicited result code
// should be sent to destination.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::SendUnsolicitedResult( CATExtPluginBase* aPlugin,
                                           const TDesC8& aAT )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    iMetadata->CompleteUrcMessage( aAT, aPlugin );
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// From MATExtPluginObserver.
// Called by Extension Plugins to inform ATEXT that a command handling has
// been completed or rejected.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::HandleCommandCompleted( CATExtPluginBase* aPlugin,
                                            TInt aError,
                                            TATExtensionReplyType aReplyType )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TInt retVal = iMetadata->CompleteCommandMessage( aPlugin,
                                                     aError,
                                                     EFalse,      // no error reply
                                                     aReplyType,  // type of reply
                                                     ETrue );     // multipart
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// From MATExtPluginObserver.
// Called by concrete extension plugin to inform the array of supported
// commands should be returned
// ---------------------------------------------------------------------------
//
TInt CATExtSession::GetSupportedCommands( CATExtPluginBase* aPlugin,
                                          RPointerArray<HBufC8>& aCmds )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TInt retVal = iMetadata->GetSupportedCommands( aPlugin, aCmds );
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// From MATExtPluginObserver.
// Called by the destructor of CATExtPluginBase. A concrete service provider
// implementation should not touch this.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::ATExtPluginClosed( CATExtPluginBase* aPlugin )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    TInt retVal = iMetadata->RemoveImplementationInstance( aPlugin );
    // "delete this" used in plugin. Plugin must cancel asynchronous
    // operations in its destructor to complete iCommandMessage and
    // iUnsolicitedMessage
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// From class MATExtListen.
// Notifies about an installed plugin.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::NotifyPluginInstallation(
    TUid& /*aIfUid*/,
    CImplementationInformation* aImplInfo )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata || !aImplInfo )
        {
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    // 1. Add the new UID to metadata.
    TRAPD( retTrap, iMetadata->AddImplementationL( aImplInfo ) );
    if ( retTrap != KErrNone )
        {
        TRACE_FUNC_EXIT
        return retTrap;
        }
    // 2. Lock the entry in metadata.
    TUid pluginUid = aImplInfo->ImplementationUid();
    TInt retTemp = iMetadata->LockPluginAccess( pluginUid );
    if ( retTemp != KErrNone )
        {
        TRACE_FUNC_EXIT
        return retTemp;
        }
    // 3. Notify client of installation.
    if ( iEcomStatusMessage.Handle() )
        {
        TPckg<TUid> pluginUidPckg( pluginUid );
        retTemp = iEcomStatusMessage.Write(
            EATExtReceiveEcomPluginChangeParamUid,
            pluginUidPckg );
        TRACE_INFO(( _L("Write returned %d"), retTemp ));
        TPckg<TATExtensionEcomType> ecomType( EEcomTypeInstall );
        retTemp = iEcomStatusMessage.Write(
            EATExtReceiveEcomPluginChangeParamType,
            ecomType );
        TRACE_INFO(( _L("Write returned %d"), retTemp ));
        iEcomStatusMessage.Complete( KErrNone );
        }
    // 4. When client notifies installation, remove the lock from metadata.
    // See IpcReportListenerUpdateReady() for this.
    TRACE_FUNC_EXIT
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// From MATExtListen.
// Notifies about an uninstalled plugin.
// ---------------------------------------------------------------------------
//
TInt CATExtSession::NotifyPluginUninstallation( TUid& /*aIfUid*/,
                                                TUid& aPluginUid )
    {
    TRACE_FUNC_ENTRY
    if ( !iMetadata )
        {
        TRACE_FUNC_EXIT
        return KErrGeneral;
        }
    // 1. Lock the access to metadata from the responsible plugin UID.
    TInt retTemp = iMetadata->LockPluginAccess( aPluginUid );
    if ( retTemp != KErrNone )
        {
        TRACE_FUNC_EXIT
        return retTemp;
        }
    // 2. Notify client of removal.
    if ( iEcomStatusMessage.Handle() )
        {
        TPckg<TUid> pluginUid( aPluginUid );
        retTemp = iEcomStatusMessage.Write(
            EATExtReceiveEcomPluginChangeParamUid,
            pluginUid );
        TRACE_INFO(( _L("Write returned %d"), retTemp ));
        TPckg<TATExtensionEcomType> ecomType( EEcomTypeUninstall );
        retTemp = iEcomStatusMessage.Write(
            EATExtReceiveEcomPluginChangeParamType,
            ecomType );
        TRACE_INFO(( _L("Write returned %d"), retTemp ));
        iEcomStatusMessage.Complete( KErrNone );
        }
    // 3. When client notifies of removal, remove the locked entry from metadata.
    // See IpcReportListenerUpdateReady() for this.
    TRACE_FUNC_EXIT
    return KErrNone;
    }