transport: Change transport api to allow for wait_for_card/connect/disconnect

This way, we can re-use the same transport parameters for several
cards for a future batch mode

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
diff --git a/pySim-prog.py b/pySim-prog.py
index b7fc793..df66b80 100755
--- a/pySim-prog.py
+++ b/pySim-prog.py
@@ -302,6 +302,9 @@
 		sl = PcscSimLink(opts.pcsc_dev)
 	scc = SimCardCommands(transport=sl)
 
+	print "Insert Card now"
+	sl.wait_for_card()
+
 	# Detect type if needed
 	card = None
 	ctypes = dict([(kls.name, kls) for kls in _cards_classes])
diff --git a/pySim/transport/__init__.py b/pySim/transport/__init__.py
index c9715fc..dd04bba 100644
--- a/pySim/transport/__init__.py
+++ b/pySim/transport/__init__.py
@@ -23,6 +23,25 @@
 
 class LinkBase(object):
 
+	def wait_for_card(self, timeout=None, newcardonly=False):
+		"""wait_for_card(): Wait for a card and connect to it
+
+		   timeout     : Maximum wait time (None=no timeout)
+		   newcardonly : Should we wait for a new card, or an already
+		                 inserted one ?
+		"""
+		pass
+
+	def connect(self):
+		"""connect(): Connect to a card immediately
+		"""
+		pass
+
+	def disconnect(self):
+		"""disconnect(): Disconnect from card
+		"""
+		pass
+
 	def reset_card(self):
 		"""reset_card(): Resets the card (power down/up)
 		"""
diff --git a/pySim/transport/pcsc.py b/pySim/transport/pcsc.py
index 5d92009..dc040c5 100644
--- a/pySim/transport/pcsc.py
+++ b/pySim/transport/pcsc.py
@@ -22,7 +22,8 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-from smartcard.Exceptions import NoCardException
+from smartcard.CardRequest import CardRequest
+from smartcard.Exceptions import NoCardException, CardRequestTimeoutException
 from smartcard.System import readers
 
 from pySim.exceptions import NoCardError
@@ -34,16 +35,30 @@
 
 	def __init__(self, reader_number=0):
 		r = readers();
-		try:
-			self._con = r[reader_number].createConnection()
-			self._con.connect()
-		except NoCardException:
-			raise NoCardError()
+		self._reader = r[reader_number]
+		self._con = self._reader.createConnection()
 
 	def __del__(self):
 		self._con.disconnect()
 		return
 
+	def wait_for_card(self, timeout=None, newcardonly=False):
+		cr = CardRequest(readers=[self._reader], timeout=timeout, newcardonly=newcardonly)
+		try:
+			cr.waitforcard()
+		except CardRequestTimeoutException:
+			raise NoCardError()
+		self.connect()
+
+	def connect(self):
+		try:
+			self._con.connect()
+		except NoCardException:
+			raise NoCardError()
+
+	def disconnect(self):
+		self._con.disconnect()
+
 	def reset_card(self):
 		self._con.disconnect()
 		try:
diff --git a/pySim/transport/serial.py b/pySim/transport/serial.py
index d384146..825c458 100644
--- a/pySim/transport/serial.py
+++ b/pySim/transport/serial.py
@@ -47,16 +47,61 @@
 		self._rst_pin = rst
 		self._debug = debug
 
-		rv = self.reset_card()
+	def __del__(self):
+		self._sl.close()
+
+	def wait_for_card(self, timeout=None, newcardonly=False):
+		# Direct try
+		existing = False
+
+		try:
+			self.reset_card()
+			if not newcardonly:
+				return
+			else:
+				existing = True
+		except NoCardError:
+			pass
+
+		# Poll ...
+		mt = time.time() + timeout if timeout is not None else None
+		pe = 0
+
+		while (mt is None) or (time.time() < mt):
+			try:
+				time.sleep(0.5)
+				self.reset_card()
+				if not existing:
+					return
+			except NoCardError:
+				existing = False
+			except ProtocolError:
+				if existing:
+					existing = False
+				else:
+					# Tolerate a couple of protocol error ... can happen if
+					# we try when the card is 'half' inserted
+					pe += 1
+					if (pe > 2):
+						raise
+
+		# Timed out ...
+		raise NoCardError()
+
+	def connect(self):
+		self.reset_card()
+
+	def disconnect(self):
+		pass # Nothing to do really ...
+
+	def reset_card(self):
+		rv = self._reset_card()
 		if rv == 0:
 			raise NoCardError()
 		elif rv < 0:
 			raise ProtocolError()
 
-	def __del__(self):
-		self._sl.close()
-
-	def reset_card(self):
+	def _reset_card(self):
 		rst_meth_map = {
 			'rts': self._sl.setRTS,
 			'dtr': self._sl.setDTR,