/** * Copyright (c) 2014-2020 Martin Paljak * <p> * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * <p> * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * <p> * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package apdu4j.p; import apdu4j.CardBIBO; import apdu4j.SCard; import apdu4j.TagRemovedException; import apdu4j.TerminalManager; import apdu4j.i.TouchTerminalApp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.smartcardio.Card; import javax.smartcardio.CardException; import javax.smartcardio.CardTerminal; public final class TouchTerminalRunner { private static final Logger logger = LoggerFactory.getLogger(TouchTerminalRunner.class); public static int run(CardTerminal reader, TouchTerminalApp app, String[] args) { int r = app.onStart(args); if (r != 0) return r; String protocol = System.getProperty(CardTerminalApp.PROTOCOL_PROPERTY, "*"); try { waitForCardAbsent(reader); while (!Thread.currentThread().isInterrupted()) { waitForCard(reader, 60); Card card; try { card = reader.connect(protocol); } catch (CardException e) { System.out.println(e.getMessage()); if (TerminalManager.getExceptionMessage(e).equals(SCard.SCARD_W_UNPOWERED_CARD)) { // Contact card not yet powered up Thread.sleep(100); card = reader.connect(protocol); } else { System.err.println("W: Too fast, try again!"); Thread.sleep(300); // to avoid instant re-powering continue; } } try { app.onTouch(CardBIBO.wrap(card)); card.disconnect(true); } catch (TagRemovedException e) { logger.debug("Tag removed while onTouch"); } int i = 0; boolean removed; // Wait until card is removed do { removed = reader.waitForCardAbsent(1000); if (i >= 10 && i % 10 == 0) { System.err.println("W: Remove card!"); } } while (removed == false && i++ < 60); // Final check. If card has not been removed, fail if (!removed) { System.err.println("E: Stuck card detected: " + reader.getName()); // possibly exit here } Thread.sleep(300); // to avoid re-powering } } catch (CardException e) { e.printStackTrace(); return 1; } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); return 1; } return 0; } public static boolean waitForCard(CardTerminal t, int seconds) throws CardException { logger.trace("Waiting for card..."); final int dot = 3; final int n = seconds / dot; boolean found = false; System.err.print("\nWaiting for card ..."); for (int i = 0; i < n && !found && !Thread.currentThread().isInterrupted(); i++) { found = t.waitForCardPresent(dot * 1000); System.err.print("."); } System.err.println(); return found; } private static void waitForCardAbsent(CardTerminal t) throws CardException { logger.trace("Waiting for card removal..."); boolean found = false; for (int i = 20; i > 0 && !found && !Thread.currentThread().isInterrupted(); i--) { found = t.waitForCardAbsent(3000); // Wait for a minute in 3 second rounds if (!found) System.err.println("Remove card and touch again"); } System.err.println(); if (!found) { System.err.println("Timeout, bye!"); } } }