aboutsummaryrefslogtreecommitdiffstats
path: root/cards
diff options
context:
space:
mode:
authorHenryk Plötz <henryk@ploetzli.ch>2010-02-24 02:57:44 +0100
committerHenryk Plötz <henryk@ploetzli.ch>2010-02-24 02:57:44 +0100
commit86c77780224304db61378b6e01f2f86c48e50fb3 (patch)
treed6dce1830f4c027b3d7f36a5dd6bf7dbf09d3d3d /cards
parent2f244a208318cd4c40f99dbf1f09101878e14dc0 (diff)
Add VRS application and GUI (Public transport in Koeln and Bonn)
Diffstat (limited to 'cards')
-rw-r--r--cards/vrs_application.py117
1 files changed, 117 insertions, 0 deletions
diff --git a/cards/vrs_application.py b/cards/vrs_application.py
new file mode 100644
index 0000000..549bb84
--- /dev/null
+++ b/cards/vrs_application.py
@@ -0,0 +1,117 @@
+from generic_application import Application
+import struct, sha, binascii, os, datetime, sys, time
+from iso_7816_4_card import ISO_7816_4_Card
+import utils, TLV_utils, generic_card
+
+
+class VRS_Application(Application):
+ DRIVER_NAME = ["VRS"]
+
+ AID_LIST = [
+ "d2760000254b414e4d303100",
+ "d2760001354b414e4d303100",
+ ]
+
+class VrsTicket(object):
+ def __init__(self):
+ self._birthdate = None
+ self._maindata = []
+ self._mainblob = None
+ self._rawdata = None
+ self._tlvdata = None
+ self._card = None
+
+ def from_card(cls, card, record_no = 1):
+ if not isinstance(card, VRS_Application):
+ if not isinstance(card, ISO_7816_4_Card):
+ raise ValueError, "card must be a VRS_Application object or a ISO_7816_4_Card object, not %s" % type(card)
+ else:
+ result = card.select_application(binascii.a2b_hex(VRS_Application.AID_LIST[0]))
+ if not card.check_sw(result.sw):
+ raise EnvironmentError, "card did not accept SELECT APPLICATION, sw was %02x %02x" % (result.sw1, result.sw2)
+ assert isinstance(card, VRS_Application)
+
+ c = cls()
+ c._card = card
+
+ result = card.open_file("\x0c\x05")
+ if card.check_sw(result.sw):
+ contents = card.read_record(record_no, 4)
+ if len(contents) > 0:
+ c._parse( contents )
+ else:
+ raise KeyError, "No ticket in record no. %i" % record_no
+ else:
+ raise EnvironmentError, "card did not accept SELECT FILE, sw was %02x %02x" % (result.sw1, result.sw2)
+
+ return c
+
+ def _parse(self, contents):
+ self._rawdata = contents
+ self._tlvdata = TLV_utils.unpack(contents)
+
+ tmp = TLV_utils.tlv_find_tag(self._tlvdata, 0xEA, num_results = 1)
+ if len(tmp) == 0:
+ raise ValueError, "Can't parse information file, tag 0xEA not found"
+ tmp = TLV_utils.tlv_find_tag(tmp, 0x85, num_results = 1)
+ if len(tmp) == 0:
+ raise ValueError, "Can't parse information file, tag 0x85 not found"
+ self._mainblob = tmp[0][2]
+
+ tmp = self._mainblob
+ some_id, tmp = tmp[:4], tmp[4:]
+
+ ascii_field_len = ord(tmp[0])
+ tmp = tmp[1:]
+
+ ascii_field, tmp = tmp[:ascii_field_len], tmp[ascii_field_len:]
+ self._maindata = ascii_field.split(" ")
+
+ if len(tmp) > 0:
+ if tmp[0] == "\x01":
+ tmp = tmp[1:]
+ birthdate_bin, tmp = tmp[:4], tmp[4:]
+
+ birthdate = binascii.b2a_hex(birthdate_bin)
+ self._birthdate = datetime.date( int(birthdate[0:4]), int(birthdate[4:6]), int(birthdate[6:8]) )
+
+ if len(tmp) > 0:
+ print "Warning: unparsed data trailing: %r" % tmp
+
+ from_card = classmethod(from_card)
+
+ def getter(index, encoding=None):
+ def g(self):
+ if self._maindata is None or len(self._maindata) <= index:
+ return None
+ if encoding is None:
+ return unicode( self._maindata[index] )
+ else:
+ return unicode( self._maindata[index], encoding = encoding )
+
+ return g
+
+ def _get_alter(self):
+ now = datetime.date.fromtimestamp( time.time() )
+ diff = now.year-self.geburtsdatum.year
+ thisyearsbirthday = datetime.date( now.year, self.geburtsdatum.month, self.geburtsdatum.day )
+ if now < thisyearsbirthday: diff = diff - 1
+ return diff
+
+ def __str__(self):
+ return "%s: %s %s" % (self.tickettyp, self.name_klar, self.abonr)
+
+
+ tickettyp = property(getter(0))
+ rnummer = property(getter(1))
+ gueltigkeit = property(getter(2))
+ feld4 = property(getter(3))
+ name_raw = property(getter(4))
+ vorname = property(lambda self: self.name_raw and "".join(self.name_raw.split(",_")[1:]).replace("_", " "))
+ nachname = property(lambda self: self.name_raw and "".join(self.name_raw.split(",_")[:1]).replace("_", " "))
+ name_klar = property(lambda self: self.vorname + " " + self.nachname)
+ schule = abonr = property(getter(5,'cp850'))
+ geburtsdatum = property(lambda self: self._birthdate)
+ alter = property(lambda self: self._birthdate and self._get_alter())
+
+