wim/SwimReader/src/SwimReader.cpp
changeset 0 164170e6151a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wim/SwimReader/src/SwimReader.cpp	Tue Jan 26 15:20:08 2010 +0200
@@ -0,0 +1,699 @@
+/*
+* Copyright (c) 2003 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:  Implements the functional and communication levels of module
+*
+*/
+
+
+// INCLUDE FILES 
+#include    "SwimReader.h"
+#include    "SwimReaderIF.h"
+#include    "rmmcustomapi.h"    // TApdu
+#include    "WimTrace.h"        // For trace logging
+#include    <mmtsy_names.h>     // TSY and Phone name
+
+#ifdef _DEBUG
+#include    <flogger.h>
+#endif
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CSwimReader::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CSwimReader* CSwimReader::NewL( CSwimReaderIF* aInterface )
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::NewL|Begin"));
+    CSwimReader* self = new( ELeave ) CSwimReader( aInterface );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::CSwimReader
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CSwimReader::CSwimReader( CSwimReaderIF* aInterface )
+    : CActive( EPriorityNormal )
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::CSwimReader|Begin"));
+    CActiveScheduler::Add( this );
+    iInterface = aInterface;
+    iReaderAttached = ETrue;
+    
+    // Currently (and probably always) APDU interface and forecoming
+    // APDU server will support only one reader, which number is 0.
+    iPreferredReader = 0;
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CSwimReader::ConstructL()
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::ConstructL|Begin"));
+#ifdef _DEBUG        
+    RFileLogger::WriteFormat( KSwimReaderLogDir, KSwimReaderLogFileName,     
+        EFileLoggingModeAppend, 
+        _L( "CSwimReader::ConstructL: Creating new RTelServer object...\n" ) );
+#endif
+    iEtelServer = new( ELeave ) RTelServer();    
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader:: ~CSwimReader
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CSwimReader::~CSwimReader()
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::~CSwimReader|Begin"));
+    Close();
+    CleanUp();
+    delete iMsg;
+    delete iEtelServer;
+    delete iTempBuf;
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::APDUReqL
+// Send APDU command aCommandAPDU to the ETEL server.
+// Response is set to aResponseAPDU.
+// -----------------------------------------------------------------------------
+//
+void CSwimReader::APDUReqL(
+    TRequestStatus& aStatus,
+    const TPtrC8&   aCommandAPDU,
+    TPtr8&          aResponseAPDU,    
+    TUint8          aServiceType,
+    TUint8          aCardReader,
+    TUint8          aAppType,
+    TUint8          aPaddingByte )
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::APDUReqL1|Begin"));
+    iClientStatus = &aStatus;
+    aStatus = KRequestPending;
+    APDUReqL( aCommandAPDU, aResponseAPDU, aServiceType, aCardReader, 
+              aAppType, aPaddingByte );
+    iPhase = EAPDURequest;
+    SetActive();
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::Close
+// Close ETEL connection and connection to CustomAPI.
+// -----------------------------------------------------------------------------
+//
+void CSwimReader::Close()
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::Close|Begin"));
+    Cancel();
+    if ( iOpen )
+        {
+        iApdu.Close();
+        iEtelServer->Close();
+        iOpen = EFalse;
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CSwimReader::DoCancel
+// Asynchronous request cancelled
+// -----------------------------------------------------------------------------
+//
+void CSwimReader::DoCancel()
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::DoCancel|Begin"));
+    
+    if( iPhase == EAPDURequest )
+        {
+    	iApdu.CancelAPDUReq();
+        }
+        
+#ifdef _DEBUG            
+    RFileLogger::WriteFormat( KSwimReaderLogDir, KSwimReaderLogFileName,         
+        EFileLoggingModeAppend, 
+        _L( "CSwimReader::DoCancel: Clean up.\n" ) );
+#endif
+    CleanUp();
+#ifdef _DEBUG            
+    RFileLogger::WriteFormat( KSwimReaderLogDir, KSwimReaderLogFileName,         
+        EFileLoggingModeAppend, 
+        _L( "CSwimReader::DoCancel: Complete request with status %d.\n" ),
+            iStatus.Int() );
+#endif
+    User::RequestComplete( iClientStatus, iStatus.Int() );
+
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::PreferredReaderStatus
+// Get preferred reader statuses from the iPreferredReaderStatus member.
+// -----------------------------------------------------------------------------
+//
+void CSwimReader::PreferredReaderStatus( TUint8& aReaderStatus )
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::PreferredReaderStatus|Begin"));
+    aReaderStatus = iPreferredReaderStatus;
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::SelectCardReader
+// From given status bytes, select a card reader, which
+// is present and card is also present in the reader.
+// -----------------------------------------------------------------------------
+//
+TUint8 CSwimReader::SelectCardReader(
+    TDesC8&  aReaderStatuses,
+    TUint8& aPreferredReaderStatus,
+    TUint8  aOldPreferredReader /* = NO_PREFERRED_READER */ )
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::SelectCardReader|Begin"));
+    TInt i;
+    TInt size;
+    TUint8 readerStatus;
+
+    size = aReaderStatuses.Length();
+
+    for ( i = 0; i < size; i++ )
+        {
+        readerStatus = aReaderStatuses[i];
+
+        _WIMTRACE2(_L("WIM|SwimReader|CSwimReader::SelectCardReader|ReaderStatus=%d"), 
+            (TUint8)aReaderStatuses[i]);
+
+        // First check that this isn't the reader the caller has
+        // already tried to use and find inappropriate for some reason.
+        if ( i != aOldPreferredReader )
+            {
+            // If reader and card are present, this reader is good for us.
+            if ( (readerStatus & KCardReaderPresent) &&
+                (readerStatus & KCardPresent) )
+                {
+                aPreferredReaderStatus = readerStatus;
+                _WIMTRACE2(_L("WIM|SwimReader|CSwimReader::SelectCardReader|PreferredReaderStatus1=%d"),
+                    readerStatus);
+
+                // Reader number is stored in first three bits,
+                // so return only them.
+                return ( static_cast< TUint8 >( readerStatus & KIdentityMask ) );
+                }
+            }
+        }
+
+    // If not found, use a one where reader is present.
+    for ( i = 0; i < size; i++ )
+        {
+        readerStatus = aReaderStatuses[i];
+
+        // First check that this isn't the reader the caller has
+        // already tried to use and find inappropriate for some reason.
+        if ( i != aOldPreferredReader )
+            {
+            // If reader is present, this reader is good for us.
+            if ( readerStatus & KCardReaderPresent )
+                {
+                _WIMTRACE2(_L("WIM|SwimReader|CSwimReader::SelectCardReader|PreferredReaderStatus2=%d"),
+                    readerStatus);
+                aPreferredReaderStatus = readerStatus;
+
+                // Reader number is stored in first three bits,
+                // so return only them.
+                return ( static_cast< TUint8 >( readerStatus & KIdentityMask ) );
+                }
+            }
+        }
+
+    // If nothing found, return a one caller gave to us.
+    return aOldPreferredReader;
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::SetCardInserted
+// Set card inserted
+// -----------------------------------------------------------------------------
+//
+void CSwimReader::SetCardInserted( TBool aIsInserted )
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::SetCardInserted|Begin"));
+    iCardInserted = aIsInserted;
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::WakeUpL
+// Initializes the reader. Also make APDU_LIST to get
+// all statuses of card readers attached to the device.
+// -----------------------------------------------------------------------------
+//
+void CSwimReader::WakeUpL( TRequestStatus& aStatus, TDes8& aHistoricals )
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::WakeUpL|Begin"));
+    iHistoricals = aHistoricals;
+    iClientStatus = &aStatus;
+    aStatus = KRequestPending;
+
+    // Set reader not open
+    iOpen = EFalse;
+
+    _WIMTRACE2(_L("WIM|SwimReader|CSwimReader::WakeUpL|iPreferredReader=%d"),
+        iPreferredReader);
+
+    // If WakeUp failed last time, preferred reader might be initialized
+    // wrong, use reader 0
+    if ( iPreferredReader == KNoPreferredReader )
+        {
+        iPreferredReader = 0;
+        _WIMTRACE(_L("WIM|SwimReader|CSwimReader::WakeUpL|iPreferredReader changed to 0"));
+        }
+    
+    TInt ret = 0;
+
+    // Connect to the Etel server.
+    ret = iEtelServer->Connect();
+    if ( ret != KErrNone )
+        {
+#ifdef _DEBUG        
+        RFileLogger::WriteFormat( KSwimReaderLogDir, KSwimReaderLogFileName,
+            EFileLoggingModeAppend, 
+            _L( "CSwimReader::WakeUpL: connection to etel server failed: %d" ),
+            ret );
+#endif
+        User::Leave( ret );
+        }
+
+    // Load phone module.
+    ret = iEtelServer->LoadPhoneModule( KMmTsyModuleName );
+    
+    if ( ret != KErrNone )
+        {
+#ifdef _DEBUG        
+        RFileLogger::WriteFormat( KSwimReaderLogDir, KSwimReaderLogFileName,
+            EFileLoggingModeAppend, 
+            _L( "CSwimReader::WakeUpL: loading phone module failed: %d" ), 
+            ret );
+#endif
+        User::Leave( ret );
+        }
+
+    // Open CustomAPI connection
+    ret = iApdu.Open( *iEtelServer, KMmTsyPhoneName );
+
+    if ( ret != KErrNone )
+        {
+#ifdef _DEBUG        
+        RFileLogger::WriteFormat( KSwimReaderLogDir, KSwimReaderLogFileName,
+            EFileLoggingModeAppend, 
+            _L( "CSwimReader::WakeUpL: phone open failed: %d" ), 
+            ret );
+#endif
+        iEtelServer->Close();
+        User::Leave( ret );
+        }
+
+    // Make LIST to get status of only available reader.
+    if ( iReaderStatuses )
+        {
+        delete iReaderStatuses;
+        iReaderStatuses = NULL;
+        }
+    if ( iReaderStatusesPtr )
+        {
+        delete iReaderStatusesPtr;
+        iReaderStatusesPtr = NULL;
+        }
+    iReaderStatuses = HBufC8::NewL( KMaxReaderAmount );
+    iReaderStatusesPtr = new ( ELeave ) TPtr8( iReaderStatuses->Des() );
+
+#ifdef _DEBUG        
+        RFileLogger::WriteFormat( KSwimReaderLogDir, KSwimReaderLogFileName,
+            EFileLoggingModeAppend, 
+            _L( "CSwimReader::WakeUpL: Getting list..." ) );
+#endif
+    _WIMTRACE2(_L("WIM|SwimReader|CSwimReader::WakeUpL|iPreferredReader=%d"),
+        iPreferredReader);
+
+    TRAPD( err, APDUReqL( iCmdBytes, *iReaderStatusesPtr, KList,
+                          iPreferredReader ) );
+
+    if ( err )
+        {
+#ifdef _DEBUG        
+        RFileLogger::WriteFormat( KSwimReaderLogDir, KSwimReaderLogFileName,
+            EFileLoggingModeAppend, 
+            _L( "CSwimReader::WakeUpL: get list failed: %d" ), err );
+#endif
+        iInterface->Notify( EReaderRemoved );
+        iApdu.Close();
+        iEtelServer->Close();
+        User::RequestComplete( iClientStatus, err );
+        }
+    else
+        {
+        _WIMTRACE2(_L("WIM|SwimReader|CSwimReader::WakeUpL|*iReaderStatusesPtr=%d"),
+            *iReaderStatusesPtr);
+        iPhase = EWakeUpAPDURequest;
+        SetActive();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::APDUReqL
+// Send APDU command aCommandAPDU to the ETEL server.
+// Response is set to aResponseAPDU.
+// -----------------------------------------------------------------------------
+//
+void CSwimReader::APDUReqL(
+    const TPtrC8& aCommandAPDU,
+    TPtr8&        aResponseAPDU,    
+    TUint8        aServiceType,
+    TUint8        aCardReader,
+    TUint8        aAppType,
+    TUint8        aPaddingByte )
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::CSwimReaderLauncher|Begin"));
+    // If reader not given, use preferred reader,
+    if ( aCardReader == KNoPreferredReader )
+        {
+        // If preferred reader is not set, quess 0.
+        if ( iPreferredReader != KNoPreferredReader )
+            {
+            aCardReader = iPreferredReader;
+            }
+        else
+            {
+            aCardReader = 0;
+            }
+        }
+
+    iHeader.SetHeader( aServiceType, aCardReader, aAppType, aPaddingByte );
+
+    // ...and call next function.
+    APDUReqL( aCommandAPDU, aResponseAPDU, iHeader );
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::APDUReqL
+// Send APDU command aCommandAPDU to the ETEL server.
+// Response is set to aResponseAPDU.
+// -----------------------------------------------------------------------------
+//
+void CSwimReader::APDUReqL(
+    const TPtrC8&       aCommandAPDU,
+    TPtr8&              aResponseAPDU,
+    TSwimApduReqHeader& aReqHeader )
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::APDUReqL|Begin"));
+    iReqHeader = &aReqHeader;
+    iResponseAPDU = &aResponseAPDU; 
+    iTempBuf = 0;
+    
+    if ( iMsg )
+    {
+    delete iMsg;
+    iMsg = NULL;	
+    }
+    
+    iMsg = new( ELeave ) RMmCustomAPI::TApdu();   
+ 
+    // Set APDU header to APDU message.
+    iMsg->iInfo = aReqHeader.Data();
+
+    // Copy command APDU to response APDU and use it to both
+    // transfer request to lower levels and to receive response.
+    if ( &aCommandAPDU )
+        {
+        iMaxLen = aResponseAPDU.MaxLength();
+
+        if ( iMaxLen >= aCommandAPDU.Length() )
+            {
+            aResponseAPDU = aCommandAPDU;
+
+            iMsg->iData = &aResponseAPDU;
+            }
+        else
+            {
+            // Response APDU isn't long enough for Command APDU,
+            // which makes a situation a little more complicated.
+            // Create a new buffer with enough space.
+            if( iTempBuf )
+            {
+            delete iTempBuf;
+            iTempBuf = NULL;
+            }
+            if( iTempPtr )
+            {
+            delete iTempPtr;
+            iTempPtr = NULL;
+            }
+            
+	    iTempBuf = HBufC8::NewL( aCommandAPDU.Length() );
+            iTempPtr = new( ELeave )TPtr8( iTempBuf->Des() );
+	    iTempPtr->Copy( aCommandAPDU );
+	    iMsg->iData = iTempPtr;
+            }
+        }
+    iApdu.APDUReq( iStatus, *iMsg );
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::CleanUp
+// Clean up allocated buffers
+// -----------------------------------------------------------------------------
+//
+void CSwimReader::CleanUp()
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::CleanUp|Begin"));
+    delete iReaderStatusesPtr;
+    iReaderStatusesPtr = NULL;
+    delete iReaderStatuses;
+    iReaderStatuses = NULL;
+    delete iTempBuf;
+    iTempBuf = NULL;
+    delete iMsg;
+    iMsg = NULL;
+    delete iTempPtr;
+    iTempPtr = NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::RunL
+// Handle asyncronous APDU requests
+// -----------------------------------------------------------------------------
+//
+void CSwimReader::RunL()
+    {
+    _WIMTRACE3(_L("WIM|SwimReader|CSwimReader::RunL|iPhase=%d, iStatus=%d"),
+        iPhase, iStatus.Int() );
+
+    if ( iStatus.Int() == 0 )
+        {
+        switch ( iPhase )
+            {
+            case EWakeUpAPDURequest:
+                {
+                TInt error = HandleOpenAPDUReq();
+
+                iOpen = ETrue;
+#ifdef _DEBUG        
+                RFileLogger::WriteFormat( KSwimReaderLogDir, 
+                    KSwimReaderLogFileName, EFileLoggingModeAppend, 
+                    _L( "CSwimReader::RunL: WakeUp completed: %d" ), 
+                    error );
+#endif
+
+                User::RequestComplete( iClientStatus, error );
+
+                break;
+                }
+            case EAPDURequest:
+                {
+                TInt error = HandleAPDUReq();
+
+#ifdef _DEBUG        
+                RFileLogger::WriteFormat( KSwimReaderLogDir, 
+                    KSwimReaderLogFileName, EFileLoggingModeAppend, 
+                    _L( "CSwimReader::RunL: APDU request completed: %d" ), 
+                    error );
+#endif
+                User::RequestComplete( iClientStatus, error );
+                break;
+                }
+
+            }
+        }
+    else
+        {
+#ifdef _DEBUG                
+        RFileLogger::WriteFormat( KSwimReaderLogDir, KSwimReaderLogFileName,
+            EFileLoggingModeAppend, 
+            _L( "CSwimReader::RunL: Error, iPhase: %d iStatus: %d" ),
+            iPhase, iStatus.Int() );
+#endif
+        iApdu.Close();
+        iEtelServer->Close();
+        CleanUp();
+        User::RequestComplete( iClientStatus, iStatus.Int() );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::HandleAPDUReq
+// Handle APDU responses
+// -----------------------------------------------------------------------------
+//
+TInt CSwimReader::HandleAPDUReq()
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::HandleAPDUReq|Begin"));
+    TInt retValue;
+
+    delete iMsg;
+    iMsg = NULL;
+
+    // If we had to use temp buffer, copy response from
+    // temp buffer to response buffer given by a caller.
+    if ( iTempBuf != 0 )
+        {
+        iMaxLen = iResponseAPDU->MaxLength();
+
+        if ( iMaxLen >= iTempBuf->Length() )
+            {
+            *iResponseAPDU = iTempBuf->Des();
+            }
+        else
+            {
+            *iResponseAPDU = iTempBuf->Left( iMaxLen );
+            }
+
+        delete iTempBuf;
+        }
+
+    // Create TSwimApduRespHeader from response info.
+    TSwimApduRespHeader respHeader( *(iReqHeader->Data()) );
+
+    // Get APDU status from response header...
+    iApduStatus = respHeader.Status();
+
+#ifdef _DEBUG        
+    RFileLogger::WriteFormat( KSwimReaderLogDir, KSwimReaderLogFileName,
+        EFileLoggingModeAppend, 
+        _L( "CSwimReader::HandleAPDUReq: response status: %d" ),
+        iApduStatus );
+
+    RFileLogger::HexDump( KSwimReaderLogDir, KSwimReaderLogFileName,
+        EFileLoggingModeAppend, 
+        _S( "CSwimReader:: HandleAPDUReq APDU received:\n" ), 0,
+        iResponseAPDU->Ptr(), iResponseAPDU->Length() );
+#endif
+
+    // ...and switch it to SCard error codes.
+    switch ( iApduStatus )
+        {
+        case KApduOK:
+        case KErrNone: // Accept also KErrNone
+            {
+            retValue = KErrNone;
+            break;
+            }
+        case KApduTransmissionError:
+            {
+            retValue = KScReaderErrCommunicationFailure;
+            break;
+            }
+        case KApduCardMute:
+            {
+            retValue = KScReaderErrResponseTimeout;
+            break;
+            }
+        case KApduCardDisconnected:
+            {
+            retValue = KScReaderErrNoCard;
+            break;
+            }
+        case KApduError:
+            {
+            retValue = KScReaderErrCardFailure;
+            break;
+            }
+        case KApduReaderNotValid:
+            {
+            retValue = KScReaderErrNoReader;
+            break;
+            }
+        case KApduFormatError:
+            {
+            retValue = KScErrBadArgument;
+            break;
+            }
+        case KApduTypeNotValid:
+            {
+            retValue = KScErrBadArgument;
+            break;
+            }
+        // DOS SIM server errors
+        case KSimServError:
+        case KSimServNotready:
+        case KSimServNoservice:
+            {
+            retValue = KScReaderErrReaderFailure;
+            break;
+            }
+        default:
+            retValue = KScErrUnknown;
+            break;
+        }
+
+        // Check actual length of the data received and compare it to
+        // the length of the response buffer allocated by the caller.
+        if ( respHeader.DataLength() > iResponseAPDU->MaxLength() 
+             && !retValue )
+            {
+            // If there was more data than fitted to the buffer, tell to the 
+            // caller that the buffer was insufficient.
+            retValue = KScErrInsufficientBuffer;
+            }
+        _WIMTRACE2(_L("WIM|SwimReader|CSwimReader::HandleAPDUReq|return %d"),
+            retValue);
+        return retValue;
+    }
+
+// -----------------------------------------------------------------------------
+// CSwimReader::HandleOpenAPDUReq
+// Handle APDU request for GetReaderList request 
+// -----------------------------------------------------------------------------
+//
+TInt CSwimReader::HandleOpenAPDUReq()
+    {
+    _WIMTRACE(_L("WIM|SwimReader|CSwimReader::HandleOpenAPDUReq|Begin"));
+    TInt error = HandleAPDUReq();
+
+    if ( error == KErrNone )
+        {
+        // Select one reader, which looks like a most promising
+        // candidate to contain something useful.
+        iPreferredReader = SelectCardReader( *iReaderStatuses, 
+                                             iPreferredReaderStatus );
+        }
+    return error;
+    }
+
+// End of File