diff -r 000000000000 -r 164170e6151a wim/SwimReader/src/SwimReader.cpp --- /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 // TSY and Phone name + +#ifdef _DEBUG +#include +#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