/****************************************************************************
* Copyright (C) 2012 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
* This file is part of the Open eCard App.
*
* GNU General Public License Usage
* This file may be used under the terms of the GNU General Public
* License version 3.0 as published by the Free Software Foundation
* and appearing in the file LICENSE.GPL included in the packaging of
* this file. Please review the following information to ensure the
* GNU General Public License version 3.0 requirements will be met:
* http://www.gnu.org/copyleft/gpl.html.
*
* Other Usage
* Alternatively, this file may be used in accordance with the terms
* and conditions contained in a signed written agreement between
* you and ecsec GmbH.
*
***************************************************************************/
package org.openecard.ifd.scio.wrapper;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import javax.annotation.Nonnull;
import javax.smartcardio.ATR;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import org.openecard.common.ECardConstants;
import org.openecard.ifd.scio.EventListener;
import org.openecard.ifd.scio.IFDException;
import org.openecard.ifd.scio.reader.PCSCFeatures;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Tobias Wich <tobias.wich@ecsec.de>
*/
public class SCCard {
private static final Logger _logger = LoggerFactory.getLogger(SCCard.class);
private final Card card;
private final SCTerminal terminal;
private Map<Integer,Integer> featureCodes;
private final ConcurrentSkipListMap<byte[],SCChannel> scChannels;
public SCCard(Card card, SCTerminal terminal) {
this.card = card;
this.terminal = terminal;
this.scChannels = new ConcurrentSkipListMap<byte[], SCChannel>(new ByteArrayComparator());
}
public byte[] controlCommand(int controlCode, byte[] commandData) throws CardException {
// pause background threads talking to PCSC
EventListener.pause();
byte[] result = card.transmitControlCommand(controlCode, commandData);
return result;
}
@Nonnull
public Map<Integer,Integer> getFeatureCodes() throws CardException {
if (featureCodes == null) {
int code = PCSCFeatures.GET_FEATURE_REQUEST_CTLCODE();
try {
byte[] response = controlCommand(code, new byte[0]);
featureCodes = PCSCFeatures.featureMapFromRequest(response);
} catch (CardException ex) {
// TODO: remove this workaround by supporting feature requests under all systems and all readers
_logger.warn("Unable to request features from reader." ,ex);
featureCodes = new HashMap<Integer, Integer>();
}
}
return featureCodes;
}
public String getProtocol() {
String p = card.getProtocol();
if (p.equals("T=0")) {
return ECardConstants.IFD.Protocol.T0;
} else if (p.equals("T=1")) {
return ECardConstants.IFD.Protocol.T1;
} else {
return null;
}
}
public ATR getATR() {
return card.getATR();
}
public synchronized SCChannel getChannel(byte[] handle) throws IFDException {
SCChannel ch = scChannels.get(handle);
if (ch == null) {
IFDException ex = new IFDException(ECardConstants.Minor.IFD.INVALID_SLOT_HANDLE, "No such slot handle.");
_logger.debug(ex.getMessage(), ex);
throw ex;
}
return ch;
}
public synchronized void closeChannel(byte[] handle, boolean reset) throws IFDException {
SCChannel ch = getChannel(handle);
try {
ch.close();
scChannels.remove(handle);
// close card
if (scChannels.isEmpty()) {
terminal.removeCard();
card.disconnect(reset);
}
} catch (CardException ex) {
IFDException ifdex = new IFDException(ex);
_logger.warn(ifdex.getMessage(), ifdex);
throw ifdex;
}
}
public SCChannel addChannel(byte[] handle) throws CardException {
CardChannel channel = card.getBasicChannel();
SCChannel scChannel = new SCChannel(channel, handle);
scChannels.put(handle, scChannel);
return scChannel;
}
synchronized void disconnect() throws CardException {
card.disconnect(true);
}
public void beginExclusive() throws CardException {
card.beginExclusive();
}
public void endExclusive() throws CardException {
card.endExclusive();
}
public boolean equalCardObj(Card other) {
return card == other;
}
}