diff options
Diffstat (limited to 'gui/ireadyou.py')
-rw-r--r-- | gui/ireadyou.py | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/gui/ireadyou.py b/gui/ireadyou.py new file mode 100644 index 0000000..820723e --- /dev/null +++ b/gui/ireadyou.py @@ -0,0 +1,380 @@ +#!/usr/bin/env python +# -*- coding: iso-8859-1 -*- + +import gtk,gtk.glade,gobject +import sys, os, time +try: + import utils, TLV_utils, cards +except ImportError, e: + try: + sys.path.append(".") + import utils, TLV_utils, cards + except ImportError: + raise e + +from smartcard.CardMonitoring import CardMonitor, CardObserver +from smartcard.ReaderMonitoring import ReaderMonitor, ReaderObserver +import smartcard + +class FileLikeTextBuffer(object): + def __init__(self): + self.had_newline = True + self.buffer = gtk.TextBuffer() + self.endmark = self.buffer.create_mark("The End", self.buffer.get_end_iter(), False) + self.views = [] + + def add_view(self, v): + self.views.append(v) + v.scroll_mark_onscreen( self.endmark ) + + def writelines(self, sequence): + for s in sequence: self.write(s) + + def write(self, s): + d = "%s: " % time.strftime("%F %T") + + parts = s.split("\n") + if self.had_newline: + self.had_newline = False + s = d + else: + s = "" + + if parts[-1] == '': + del parts[-1] + self.had_newline = True + + s = s + ("\n"+d).join(parts) + if self.had_newline: s = s + "\n" + + self.buffer.insert( self.buffer.get_end_iter(), s) + for v in self.views: + v.scroll_mark_onscreen( self.endmark ) + + def flush(self): pass + + def for_stream(self, stream): + class stream_to_buf(object): + def __init__(self, parent, stream): + self.parent = parent + self.stream = stream + + def flush(self): + self.parent.flush() + self.stream.flush() + + def write(self, s): + self.parent.write(s) + self.stream.write(s) + + def writelines(self, s): + self.parent.writelines(s) + self.stream.writelines(s) + + return stream_to_buf(self, stream) + +class ireadyou(object,CardObserver,ReaderObserver): + GLADE_FILE = "gui/ireadyou/ireadyou.glade" + + def __init__(self, ticket = None): + "Create and show main window." + self.main_window_xml = gtk.glade.XML(self.GLADE_FILE, "main") + self.main_window = self.main_window_xml.get_widget("main") + + self.card_tabs = self.main_window_xml.get_widget("card_tabs") + while self.card_tabs.get_n_pages() > 0: + self.card_tabs.remove_page(0) + for t in self.CARD_TYPES: + a, b, l = gtk.Alignment(yscale=1,xscale=1,xalign=0.5,yalign=0.5), gtk.VBox(), gtk.Label(t[1]) + a.add(b) + a.show() + b.show() + l.show() + + self.card_tabs.append_page(a, tab_label=l) + + self.ticket_button_group = gtk.RadioButton() + self.ticket_button_group._ticket = None + + self.status_area = self.main_window_xml.get_widget("status_area") + self.known_readers = [] + self.known_cards = {} # Note stupid: the keys to this dict are not objects from the known_readers list but rather reader name strings + self.connected_cards = {} # Again: the keys are not cards but repr(card) + self.tickets = {} # ditto + self.ticket_displayed = None # This is either None or a tuple (card object, ticket object) + + self._update_status() + + self.logbuf = FileLikeTextBuffer() + sys.stdout = self.logbuf.for_stream(sys.stdout) + sys.stderr = self.logbuf.for_stream(sys.stderr) + self.logview = self.main_window_xml.get_widget("logview") + self.logview.set_buffer(self.logbuf.buffer) + self.logbuf.add_view(self.logview) + + signals = { + "on_exit_clicked": self.exit_clicked, + "on_main_delete_event": self.exit_clicked, + "on_main_destroy": gtk.main_quit, + } + self.main_window_xml.signal_autoconnect(signals) + + self._clear_display() + + self.rmon = ReaderMonitor() + self.cmon = CardMonitor() + + self.rmon.addObserver(self) + self.cmon.addObserver(self) + + def _clear_display(self): + self.card_tabs.set_current_page(0) + + for i in range(self.card_tabs.get_n_pages()): + a = self.card_tabs.get_nth_page(i) + vbox = a.get_child() + for c in vbox.get_children(): + vbox.remove(c) + label = self.card_tabs.get_tab_label(a) + label.set_property("sensitive", False) + + def _update_status(self): + for c in self.status_area.get_children(): + self.status_area.remove(c) + + if len(self.known_readers) == 0: + self.status_area.add( gtk.Label(u"Keine Lesegeräte angeschlossen.") ) + else: + for reader in self.known_readers: + frame = gtk.Frame(label=str(reader)) + + if len(self.known_cards[ reader.name ]) == 0: + frame.add( gtk.Label(u"Keine Karten verbunden.") ) + else: + vbox = gtk.VBox() + for card in self.known_cards[ reader.name ]: + if self.connected_cards.has_key(repr(card)): + card_ = self.connected_cards[ repr(card) ] + cardname = card_.get_driver_name() + else: + cardname = str(card) + + hbox = gtk.HBox() + cardlabel = gtk.Label( "<b>%s</b>: " % cardname ) + cardlabel.set_use_markup(True) + hbox.pack_start(cardlabel, expand=False) + + vbox2 = gtk.VBox() + hbox.pack_start(vbox2, expand=True) + for ticket in self.tickets[ repr(card) ]: + button = gtk.RadioButton(group=self.ticket_button_group, label=str(ticket), use_underline=False) + vbox2.pack_start(button, expand=False) + + button.connect("toggled", self._ticket_button_toggled) + button._ticket = (card, ticket) + + if self.ticket_displayed is not None and ticket == self.ticket_displayed[1]: + button.set_active(True) + + vbox.add(hbox) + frame.add(vbox) + + self.status_area.add(frame) + + self.status_area.show_all() + + def _format_datum(d): + return d.strftime("%x") + + CARD_TYPES = [ + (("SCHUL_T",), + "Schulticket", ( + ("Name", "name_klar", None), + ("Alter", "alter", None), + ("Geburtsdatum", "geburtsdatum", _format_datum), + ("Schule", "schule", None), + (u"Kartengültigkeit", "gueltigkeit", None), + ), + ), + (("JOBT_ERW",), + "Jobticket", ( + ("Name", "name_klar", None), + ("Geburtsdatum", "geburtsdatum", _format_datum), + (u"Kartengültigkeit", "gueltigkeit", None), + ), + ), + (("MT_ABO",), + "Monatsabo", ( + ("Abo-Nummer", "abonr", None), + (u"Kartengültigkeit", "gueltigkeit", None), + ), + ), + (None, + "Anderes", ( + ), + ), + ] + + def _ticket_button_toggled(self, togglebutton): + self.ticket_displayed = None + for b in togglebutton.get_group(): + if b.get_active(): + if hasattr(b, "_ticket"): + self.ticket_displayed = b._ticket + self._update_ticket_display() + + def _update_ticket_display(self): + self._clear_display() + if self.ticket_displayed is None: + return + + todisplay = self.ticket_displayed[1] + + for i,t in enumerate(self.CARD_TYPES): + if todisplay.tickettyp in t[0]: + break + # Note: implicit selection of the last card type when no match is found + + self.card_tabs.set_current_page(i) + a = self.card_tabs.get_nth_page(i) + vbox = a.get_child() + label = self.card_tabs.get_tab_label(a) + label.set_property("sensitive", True) + + for labeltext, propertyname, transformation in t[2]: + frame = gtk.Frame(label=labeltext) + content = getattr(todisplay, propertyname, None) + contenttext = str( transformation is not None and transformation(content) or content ) + contentlabel = gtk.Label("<b><tt><big>%s</big></tt></b>" % contenttext) + contentlabel.set_use_markup(True) + contentlabel.show() + frame.add( contentlabel ) + frame.show() + + vbox.add(frame) + + def exit_clicked(self, widget, event=None, data=None): + gtk.main_quit() + return True + + def run(self): + gtk.main() + + # From the CardObserver and ReaderObserver classes + def update( self, observable, (added, removed) ): + try: + gtk.gdk.threads_enter() + #print observable, added, removed + if observable is self.rmon.instance: + self.reader_update(observable, (added, removed) ) + elif observable is self.cmon.instance: + self.card_update(observable, (added, removed) ) + self._update_status() + self._update_ticket_display() + finally: + gtk.gdk.threads_leave() + + def reader_update( self, observable, (added, removed) ): + for r in removed: + if r in self.known_readers: + for card in list(self.known_cards[ r.name ]): + self._remove_card(card) + assert len(self.known_cards[ r.name ]) == 0 + del self.known_cards[ r.name ] + self.known_readers.remove(r) + for a in added: + if a not in self.known_readers: + self.known_readers.append(a) + self.known_cards[ a.name ] = [] + + def card_update( self, observable, (added, removed) ): + for r in removed: + if not self.known_cards.has_key(r.reader): continue + if r in self.known_cards[r.reader]: + self._remove_card(r) + for a in added: + if not self.known_cards.has_key(a.reader): continue + if a not in self.known_cards[a.reader]: + self._add_card(a) + + def _add_card(self, card): + self.known_cards[ card.reader ].append(card) + if not self.tickets.has_key( repr(card) ): + self.tickets[ repr(card) ] = [] + + conn = card.createConnection() + connected = False + try: + conn.connect() + connected = True + except smartcard.Exceptions.NoCardException, e: + pass + + if connected: + card_ = cards.new_card_object(conn) + cards.generic_card.DEBUG = False + self.connected_cards[ repr(card) ] = card_ + + for i in range(1,9): + try: + ticket = cards.vrs_application.VrsTicket.from_card(card_, record_no = i) + print "Loaded ticket '%s' from record %i" % (ticket, i) + self._add_ticket(card, ticket) + except (KeyboardInterrupt, SystemExit): + raise + except Exception,e: + if not str(e).startswith("'No ticket in record no."): + print e + + if not isinstance(card_, cards.vrs_application.VRS_Application): + break + + def _remove_card(self, card): + if self.tickets.has_key( repr(card) ): + for t in list(self.tickets[ repr(card) ]): + self._remove_ticket(card, t) + assert len(self.tickets[ repr(card) ]) == 0 + del self.tickets[ repr(card) ] + + if self.connected_cards.has_key( repr(card) ): + try: + self.connected_cards[ repr(card) ].close_card() + except smartcard.Exceptions.CardConnectionException, e: + pass + + del self.connected_cards[ repr(card) ] + self.known_cards[ card.reader ].remove(card) + + def _add_ticket(self, card, ticket): + self.tickets[ repr(card) ].append( ticket ) + if self.ticket_displayed is None: + self.ticket_displayed = ( card, ticket ) + + def _remove_ticket(self, card, ticket): + if self.ticket_displayed is not None and self.ticket_displayed[1] == ticket: + self.ticket_displayed = None + # TODO: Find a different ticket to display + self.tickets[ repr(card) ].remove(ticket) + +OPTIONS = "" +LONG_OPTIONS = [] + +if __name__ == "__main__": +## c = utils.CommandLineArgumentHelper() +## +## (options, arguments) = c.getopt(sys.argv[1:], OPTIONS, LONG_OPTIONS) +## +## card_object = c.connect() +## card = cards.new_card_object(card_object) +## #cards.generic_card.DEBUG = False +## +## print >>sys.stderr, "Using %s" % card.DRIVER_NAME +## +## if len(arguments) > 0: +## ticket = cards.vrs_application.VrsTicket.from_card(card, record_no = int(arguments[0], 0)) +## else: +## ticket = cards.vrs_application.VrsTicket.from_card(card) + + gtk.gdk.threads_init() + g = ireadyou() + g.run() |