subprocess.Popen, new pin code, disabled users, bugfixes
[uccvend-vendserver.git] / sql-edition / servers / VendServer.py
index dd2cd7d..2a9a55a 100755 (executable)
@@ -2,14 +2,15 @@
 # vim:ts=4
 
 USE_DB = 0
+USE_MIFARE = 1
 
 import ConfigParser
-import sys, os, string, re, pwd, signal, math
+import sys, os, string, re, pwd, signal, math, syslog
 import logging, logging.handlers
 from traceback import format_tb
 if USE_DB: import pg
 from time import time, sleep, mktime, localtime
-from popen2 import popen2
+from subprocess import Popen, PIPE
 from LATClient import LATClient, LATClientException
 from SerialClient import SerialClient, SerialClientException
 from VendingMachine import VendingMachine, VendingException
@@ -17,8 +18,10 @@ from MessageKeeper import MessageKeeper
 from HorizScroll import HorizScroll
 from random import random, seed
 from Idler import GreetingIdler,TrainIdler,GrayIdler,StringIdler,ClockIdler,FortuneIdler,FileIdler,PipeIdler
+from SnackConfig import get_snack#, get_snacks
 import socket
 from posix import geteuid
+from LDAPConnector import get_uid,get_uname, set_card_id
 
 CREDITS="""
 This vending machine software brought to you by:
@@ -42,15 +45,18 @@ DOOR = 1
 SWITCH = 2
 KEY = 3
 TICK = 4
+MIFARE = 5
 
 
-STATE_IDLE = 1
-STATE_DOOR_OPENING = 2
-STATE_DOOR_CLOSING = 3
-STATE_GETTING_UID = 4
-STATE_GETTING_PIN = 5
-STATE_GET_SELECTION = 6
-STATE_GRANDFATHER_CLOCK = 7
+(
+STATE_IDLE,
+STATE_DOOR_OPENING,
+STATE_DOOR_CLOSING,
+STATE_GETTING_UID,
+STATE_GETTING_PIN,
+STATE_GET_SELECTION,
+STATE_GRANDFATHER_CLOCK,
+) = range(1,8)
 
 TEXT_SPEED = 0.8
 IDLE_SPEED = 0.05
@@ -88,65 +94,122 @@ class DispenseDatabase:
 
 def scroll_options(username, mk, welcome = False):
        if welcome:
+               # Balance checking
+               acct, unused = Popen(['dispense', 'acct', username], close_fds=True, stdout=PIPE).communicate()
+               # this is fucking appalling
+               balance = acct[acct.find("$")+1:acct.find("(")].strip()
+        
                msg = [(center('WELCOME'), False, TEXT_SPEED),
-                          (center(username), False, TEXT_SPEED)]
+                          (center(username), False, TEXT_SPEED),
+                          (center(balance), False, TEXT_SPEED),]
        else:
                msg = []
        choices = ' '*10+'CHOICES: '
-       try:
-               coke_machine = file('/home/other/coke/coke_contents')
-               cokes = coke_machine.readlines()
-               coke_machine.close()
-       except:
-               cokes = []
-               pass
+
+       # Get coke contents
+       cokes = []
+       for i in range(0, 7):
+               args = ('dispense', 'iteminfo', 'coke:%i' % i)
+               info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate()
+               m = re.match("\s*[a-z]+:\d+\s+(\d+)\.(\d\d)\s+([^\n]+)", info)
+               cents = int(m.group(1))*100 + int(m.group(2))
+               cokes.append('%i %i %s' % (i, cents, m.group(3)));
+
        for c in cokes:
                c = c.strip()
                (slot_num, price, slot_name) = c.split(' ', 2)
                if slot_name == 'dead': continue
-               choices += '%s8-%s (%sc) '%(slot_num, slot_name, price)
+               choices += '%s-(%sc)-%s8 '%(slot_name, price, slot_num)
+
+#      we don't want to print snacks for now since it'll be too large
+#      and there's physical bits of paper in the machine anyway - matt
+#      try:
+#              snacks = get_snacks()
+#      except:
+#              snacks = {}
+#
+#      for slot, ( name, price ) in snacks.items():
+#              choices += '%s8-%s (%sc) ' % ( slot, name, price )
+
        choices += '55-DOOR '
-       choices += 'OR A SNACK. '
+       choices += 'OR ANOTHER SNACK. '
        choices += '99 TO READ AGAIN. '
        choices += 'CHOICE?   '
        msg.append((choices, False, None))
        mk.set_messages(msg)
 
-def get_pin(uid):
-       try:
-               info = pwd.getpwuid(uid)
-       except KeyError:
-               logging.info('getting pin for uid %d: user not in password file'%uid)
-               return None
-       if info.pw_dir == None: return False
-       pinfile = os.path.join(info.pw_dir, '.pin')
-       try:
-               s = os.stat(pinfile)
-       except OSError:
-               logging.info('getting pin for uid %d: .pin not found in home directory'%uid)
-               return None
-       if s.st_mode & 077:
-               logging.info('getting pin for uid %d: .pin has wrong permissions. Fixing.'%uid)
-               os.chmod(pinfile, 0600)
-       try:
-               f = file(pinfile)
-       except IOError:
-               logging.info('getting pin for uid %d: I cannot read pin file'%uid)
-               return None
-       pinstr = f.readline()
-       f.close()
-       if not re.search('^'+'[0-9]'*PIN_LENGTH+'$', pinstr):
-               logging.info('getting pin for uid %d: %s not a good pin'%(uid,repr(pinstr)))
-               return None
-       return int(pinstr)
+_pin_uid = 0
+_pin_uname = 'root'
+_pin_pin = '----'
+
+def _check_pin(uid, pin):
+       global _pin_uid
+       global _pin_uname
+       global _pin_pin
+       print "_check_pin('",uid,"',---)"
+       if uid != _pin_uid:
+               try:
+                       info = pwd.getpwuid(uid)
+               except KeyError:
+                       logging.info('getting pin for uid %d: user not in password file'%uid)
+                       return None
+               if info.pw_dir == None: return False
+               pinfile = os.path.join(info.pw_dir, '.pin')
+               try:
+                       s = os.stat(pinfile)
+               except OSError:
+                       logging.info('getting pin for uid %d: .pin not found in home directory'%uid)
+                       return None
+               if s.st_mode & 077:
+                       logging.info('getting pin for uid %d: .pin has wrong permissions. Fixing.'%uid)
+                       os.chmod(pinfile, 0600)
+               try:
+                       f = file(pinfile)
+               except IOError:
+                       logging.info('getting pin for uid %d: I cannot read pin file'%uid)
+                       return None
+               pinstr = f.readline()
+               f.close()
+               if not re.search('^'+'[0-9]'*PIN_LENGTH+'$', pinstr):
+                       logging.info('getting pin for uid %d: %s not a good pin'%(uid,repr(pinstr)))
+                       return None
+               _pin_uid = uid
+               _pin_pin = pinstr
+               _pin_uname = info.pw_name
+       else:
+               pinstr = _pin_pin
+       if pin == int(pinstr):
+               logging.info("Pin correct for %d",uid)
+       else:
+               logging.info("Pin incorrect for %d",uid)
+       return pin == int(pinstr)
+
+def acct_is_disabled(name=None):
+       global _pin_uname
+       if name == None:
+               name = _pin_uname
+       acct, unused = Popen(['dispense', 'acct', _pin_uname], close_fds=True, stdout=PIPE).communicate()
+       # this is fucking appalling
+       flags = acct[acct.find("(")+1:acct.find(")")].strip()
+       if 'disabled' in flags:
+               return True
+       if 'internal' in flags:
+               return True
+       return False
 
 def has_good_pin(uid):
-       return get_pin(uid) != None
+       return _check_pin(uid, None) != None
 
-def verify_user_pin(uid, pin):
-       if get_pin(uid) == pin:
+def verify_user_pin(uid, pin, skip_pin_check=False):
+       if skip_pin_check or _check_pin(uid, pin) == True:
                info = pwd.getpwuid(uid)
-               logging.info('accepted pin for uid %d (%s)'%(uid,info.pw_name))
+               if skip_pin_check:
+                       if acct_is_disabled(info.pw_name):
+                               logging.info('refused mifare for disabled acct uid %d (%s)'%(uid,info.pw_name))
+                               return '-disabled-'
+                       logging.info('accepted mifare for uid %d (%s)'%(uid,info.pw_name))
+               else:
+                       logging.info('accepted pin for uid %d (%s)'%(uid,info.pw_name))
                return info.pw_name
        else:
                logging.info('refused pin for uid %d'%(uid))
@@ -196,19 +259,21 @@ def setup_idlers(v):
                 GrayIdler(v,one="/",zero="\\"),
                ClockIdler(v),
                 GrayIdler(v,one="X",zero="O"),
-               FileIdler(v, '/usr/share/common-licenses/GPL-2'),
+               FileIdler(v, '/usr/share/common-licenses/GPL-2',affinity=2),
                 GrayIdler(v,one="*",zero="-",reorder=1),
                StringIdler(v, text=str(math.pi) + "            "),
                ClockIdler(v),
                 GrayIdler(v,one="/",zero="\\",reorder=1),
                StringIdler(v, text=str(math.e) + "            "),
                 GrayIdler(v,one="X",zero="O",reorder=1),
-               StringIdler(v, text="    I want some pizza - please call Pizza Hut Shenton Park on +61 8 9381 9979 - and order as Quinn - I am getting really hungry", repeat=False),
-               PipeIdler(v, "/usr/bin/ypcat", "passwd"),
+               StringIdler(v, text="    I want some pizza - please call Pizza Hut Shenton Park on +61 8 9381 9979 [now closed? - MSH] - and order as Quinn - I am getting really hungry", repeat=False),
+               PipeIdler(v, "/usr/bin/getent", "passwd"),
                FortuneIdler(v),
                ClockIdler(v),
                StringIdler(v),
                TrainIdler(v),
+               # "Hello World" in brainfuck
+               StringIdler(v, text=">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-] <.>+++++++++++[<++++++++>-]<-.--------.+++.------.--------.[-]>++++++++[<++++>- ]<+.[-]++++++++++."),
                ]
        disabled = [
                ]
@@ -218,6 +283,7 @@ def reset_idler(v, vstatus, t = None):
        idler = GreetingIdler(v, t)
        vstatus.time_of_next_idlestep = time()+idler.next()
        vstatus.time_of_next_idler = None
+       vstatus.time_to_autologout = None
        vstatus.change_state(STATE_IDLE, 1)
 
 def choose_idler():
@@ -348,9 +414,8 @@ def handle_get_selection_key(state, event, params, v, vstatus):
                        vstatus.cur_user = ''
                        vstatus.cur_selection = ''
                        
-                       reset_idler(v, vstatus)
-
                        vstatus.mk.set_messages([(center('BYE!'), False, 1.5)])
+                       reset_idler(v, vstatus, 2)
                        return
                vstatus.cur_selection += chr(key + ord('0'))
                vstatus.mk.set_message('SELECT: '+vstatus.cur_selection)
@@ -363,10 +428,17 @@ def handle_get_selection_key(state, event, params, v, vstatus):
                        return
                else:
                        vstatus.cur_selection += chr(key + ord('0'))
-                       make_selection(v,vstatus)
-                       vstatus.cur_selection = ''
-                       vstatus.time_to_autologout = time() + 8
-                       vstatus.last_timeout_refresh = None
+                       if vstatus.cur_user:
+                               make_selection(v,vstatus)
+                               vstatus.cur_selection = ''
+                               vstatus.time_to_autologout = time() + 8
+                               vstatus.last_timeout_refresh = None
+                       else:
+                               # Price check mode.
+                               price_check(v,vstatus)
+                               vstatus.cur_selection = ''
+                               vstatus.time_to_autologout = None
+                               vstatus.last_timeout_refresh = None
 
 def make_selection(v, vstatus):
        # should use sudo here
@@ -374,7 +446,8 @@ def make_selection(v, vstatus):
                vstatus.mk.set_message('OPENSESAME')
                logging.info('dispensing a door for %s'%vstatus.username)
                if geteuid() == 0:
-                       ret = os.system('su - "%s" -c "dispense door"'%vstatus.username)
+                       #ret = os.system('su - "%s" -c "dispense door"'%vstatus.username)
+                       ret = os.system('dispense -u "%s" door'%vstatus.username)
                else:
                        ret = os.system('dispense door')
                if ret == 0:
@@ -384,28 +457,65 @@ def make_selection(v, vstatus):
                        logging.warning('user %s tried to dispense a bad door'%vstatus.username)
                        vstatus.mk.set_message(center('BAD DOOR'))
                sleep(1)
-       elif vstatus.cur_selection == '91':
+       elif vstatus.cur_selection == '81':
                cookie(v)
        elif vstatus.cur_selection == '99':
                scroll_options(vstatus.username, vstatus.mk)
                vstatus.cur_selection = ''
                return
        elif vstatus.cur_selection[1] == '8':
-               v.display('GOT COKE?')
-               if ((os.system('su - "%s" -c "dispense %s"'%(vstatus.username, vstatus.cur_selection[0])) >> 8) != 0):
+               v.display('GOT DRINK?')
+               if ((os.system('dispense -u "%s" coke:%s'%(vstatus.username, vstatus.cur_selection[0])) >> 8) != 0):
                        v.display('SEEMS NOT')
                else:
-                       v.display('GOT COKE!')
+                       v.display('GOT DRINK!')
        else:
-               v.display(vstatus.cur_selection+' - $1.00')
-               if ((os.system('su - "%s" -c "dispense snack"'%(vstatus.username)) >> 8) == 0):
-                       v.vend(vstatus.cur_selection)
-                       v.display('THANK YOU')
-               else:
+               # first see if it's a named slot
+               try:
+                       price, shortname, name = get_snack( vstatus.cur_selection )
+               except:
+                       price, shortname, name = get_snack( '--' )
+               dollarprice = "$%.2f" % ( price / 100.0 )
+               v.display(vstatus.cur_selection+' - %s'%dollarprice)
+#              exitcode = os.system('dispense -u "%s" give \>snacksales %d "%s"'%(vstatus.username, price, name)) >> 8
+#              exitcode = os.system('dispense -u "%s" give \>sales\:snack %d "%s"'%(vstatus.username, price, name)) >> 8
+               exitcode = os.system('dispense -u "%s" snack:%s'%(vstatus.username, vstatus.cur_selection)) >> 8
+               if (exitcode == 0):
+                       # magic dispense syslog service
+                       syslog.syslog(syslog.LOG_INFO | syslog.LOG_LOCAL4, "vended %s (slot %s) for %s" % (name, vstatus.cur_selection, vstatus.username))
+                       (worked, code, string) = v.vend(vstatus.cur_selection)
+                       if worked:
+                               v.display('THANK YOU')
+                       else:
+                               print "Vend Failed:", code, string
+                               v.display('VEND FAIL')
+               elif (exitcode == 5):   # RV_BALANCE
                        v.display('NO MONEY?')
+               elif (exitcode == 4):   # RV_ARGUMENTS (zero give causes arguments)
+                       v.display('EMPTY SLOT')
+               elif (exitcode == 1):   # RV_BADITEM (Dead slot)
+                       v.display('EMPTY SLOT')
+               else:
+                       syslog.syslog(syslog.LOG_INFO | syslog.LOG_LOCAL4, "failed vending %s (slot %s) for %s (code %d)" % (name, vstatus.cur_selection, vstatus.username, exitcode))
+                       v.display('UNK ERROR')
        sleep(1)
 
 
+def price_check(v, vstatus):
+       if vstatus.cur_selection[1] == '8':
+               args = ('dispense', 'iteminfo', 'coke:' + vstatus.cur_selection[0])
+               info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate()
+               dollarprice = re.match("\s*[a-z]+:\d+\s+(\d+\.\d\d)\s+([^\n]+)", info).group(1)
+       else:
+               # first see if it's a named slot
+               try:
+                       price, shortname, name = get_snack( vstatus.cur_selection )
+               except:
+                       price, shortname, name = get_snack( '--' )
+               dollarprice = "$%.2f" % ( price / 100.0 )
+       v.display(vstatus.cur_selection+' - %s'%dollarprice)
+
+
 def handle_getting_pin_key(state, event, params, v, vstatus):
        #print "handle_getting_pin_key (s,e,p)", state, " ", event, " ", params
        key = params
@@ -445,29 +555,94 @@ def handle_getting_pin_key(state, event, params, v, vstatus):
 def handle_getting_uid_key(state, event, params, v, vstatus):
        #print "handle_getting_uid_key (s,e,p)", state, " ", event, " ", params
        key = params
+
        # complicated key handling here:
-       if len(vstatus.cur_user) < 5:
+
+       if len(vstatus.cur_user) == 0 and key == 9:
+               vstatus.cur_selection = ''
+               vstatus.time_to_autologout = None
+               vstatus.mk.set_message('PRICECHECK')
+               sleep(0.5)
+               scroll_options('', vstatus.mk)
+               vstatus.change_state(STATE_GET_SELECTION)
+               return
+
+       if len(vstatus.cur_user) <8:
                if key == 11:
                        vstatus.cur_user = ''
 
                        reset_idler(v, vstatus)
                        return
-
                vstatus.cur_user += chr(key + ord('0'))
-               vstatus.mk.set_message('UID: '+vstatus.cur_user)
-
+               #logging.info('dob: '+vstatus.cur_user)
+               if len(vstatus.cur_user) > 5:
+                       vstatus.mk.set_message('>'+vstatus.cur_user)
+               else:
+                       vstatus.mk.set_message('UID: '+vstatus.cur_user)
+       
        if len(vstatus.cur_user) == 5:
                uid = int(vstatus.cur_user)
+
+               if uid == 0:
+                       logging.info('user '+vstatus.cur_user+' has a bad PIN')
+                       pfalken="""
+CARRIER DETECTED
+
+CONNECT 128000
+
+Welcome to Picklevision Sytems, Sunnyvale, CA
+
+Greetings Professor Falken.
+
+
+
+
+Shall we play a game?
+
+
+Please choose from the following menu:
+
+1. Tic-Tac-Toe
+2. Chess
+3. Checkers
+4. Backgammon
+5. Poker
+6. Toxic and Biochemical Warfare
+7. Global Thermonuclear War
+
+7 [ENTER]
+
+Wouldn't you prefer a nice game of chess?
+
+""".replace('\n','    ')
+                       vstatus.mk.set_messages([(pfalken, False, 10)])
+                       vstatus.cur_user = ''
+                       vstatus.cur_pin = ''
+                       
+                       reset_idler(v, vstatus, 10)
+
+                       return
+
                if not has_good_pin(uid):
                        logging.info('user '+vstatus.cur_user+' has a bad PIN')
                        vstatus.mk.set_messages(
-                               [(' '*10+'INVALID PIN SETUP'+' '*10, False, 3)])
+                               [(' '*10+'INVALID PIN SETUP'+' '*11, False, 3)])
                        vstatus.cur_user = ''
                        vstatus.cur_pin = ''
                        
-                       reset_idler(v, vstatus, 5)
+                       reset_idler(v, vstatus, 3)
 
                        return
+               
+               if acct_is_disabled():
+                       logging.info('user '+vstatus.cur_user+' is disabled')
+                       vstatus.mk.set_messages(
+                               [(' '*11+'ACCOUNT DISABLED'+' '*11, False, 3)])
+                       vstatus.cur_user = ''
+                       vstatus.cur_pin = ''
+                       
+                       reset_idler(v, vstatus, 3)
+                       return
 
 
                vstatus.cur_pin = ''
@@ -493,7 +668,8 @@ def handle_idle_key(state, event, params, v, vstatus):
 
 def handle_idle_tick(state, event, params, v, vstatus):
        ### State idling
-       idle_step(vstatus)
+       if vstatus.mk.done():
+               idle_step(vstatus)
 
        if vstatus.time_of_next_idler and time() > vstatus.time_of_next_idler:
                vstatus.time_of_next_idler = time() + 30
@@ -612,24 +788,108 @@ def handle_grandfather_tick(state, event, params, v, vstatus):
                vstatus.change_state(STATE_IDLE,1)
 
 def handle_door_idle(state, event, params, v, vstatus):
+       def twiddle(clock,v,wise = 2):
+               if (clock % 4 == 0):
+                       v.display("-FEED  ME-")
+               elif (clock % 4 == 1+wise):
+                       v.display("\\FEED  ME/")
+               elif (clock % 4 == 2):
+                       v.display("-FEED  ME-")
+               elif (clock % 4 == 3-wise):
+                       v.display("/FEED  ME\\")
+
        # don't care right now.
-       pass
+       now = int(time())
+
+       if ((now % 60 % 2) == 0):
+               twiddle(now, v)
+       else:
+               twiddle(now, v, wise=0)
+
 
 def handle_door_event(state, event, params, v, vstatus):
-       if params == 1:  #door open
+       if params == 0:  #door open
                vstatus.change_state(STATE_DOOR_OPENING)
                logging.warning("Entering open door mode")
                v.display("-FEED  ME-")
                #door_open_mode(v);
                vstatus.cur_user = ''
                vstatus.cur_pin = ''
-       elif params == 0:  #door closed
+       elif params == 1:  #door closed
                vstatus.change_state(STATE_DOOR_CLOSING)
                reset_idler(v, vstatus, 3)
 
                logging.warning('Leaving open door mode')
                v.display("-YUM YUM!-")
 
+def handle_mifare_event(state, event, params, v, vstatus):
+       card_id = params
+       # Translate card_id into uid.
+       if card_id == None:
+               return
+
+       try:
+               vstatus.cur_user = get_uid(card_id)
+               logging.info('Mapped card id to uid %s'%vstatus.cur_user)
+               vstatus.username = get_uname(vstatus.cur_user)
+               if acct_is_disabled(vstatus.username):
+                       vstatus.username = '-disabled-'
+       except ValueError:
+               vstatus.username = None
+       if vstatus.username == '-disabled-':
+               v.beep(40, False)
+               vstatus.mk.set_messages(
+                       [(center('ACCT DISABLED'), False, 1.0),
+                        (center('SORRY'), False, 0.5)])
+               vstatus.cur_user = ''
+               vstatus.cur_pin = ''
+               vstatus.username = None
+       
+               reset_idler(v, vstatus, 2)
+               return
+       elif vstatus.username:
+               v.beep(0, False)
+               vstatus.cur_selection = ''
+               vstatus.change_state(STATE_GET_SELECTION)
+               scroll_options(vstatus.username, vstatus.mk, True)
+               return
+       else:
+               v.beep(40, False)
+               vstatus.mk.set_messages(
+                       [(center('BAD CARD'), False, 1.0),
+                        (center('SORRY'), False, 0.5)])
+               vstatus.cur_user = ''
+               vstatus.cur_pin = ''
+       
+               reset_idler(v, vstatus, 2)
+               return
+
+def handle_mifare_add_user_event(state, event, params, v, vstatus):
+       card_id = params
+
+       # Translate card_id into uid.
+       if card_id == None:
+               return
+
+       try:
+               if get_uid(card_id) != None:
+                       vstatus.mk.set_messages(
+                               [(center('ALREADY'), False, 0.5),
+                                (center('ENROLLED'), False, 0.5)])
+
+                       # scroll_options(vstatus.username, vstatus.mk)
+                       return
+       except ValueError:
+               pass
+
+       logging.info('Enrolling card %s to uid %s (%s)'%(card_id, vstatus.cur_user, vstatus.username))
+       set_card_id(vstatus.cur_user, card_id)
+       vstatus.mk.set_messages(
+               [(center('CARD'), False, 0.5),
+                (center('ENROLLED'), False, 0.5)])
+
+       # scroll_options(vstatus.username, vstatus.mk)
+
 def return_to_idle(state,event,params,v,vstatus):
        reset_idler(v, vstatus)
 
@@ -637,26 +897,32 @@ def create_state_table(vstatus):
        vstatus.state_table[(STATE_IDLE,TICK,1)] = handle_idle_tick
        vstatus.state_table[(STATE_IDLE,KEY,1)] = handle_idle_key
        vstatus.state_table[(STATE_IDLE,DOOR,1)] = handle_door_event
+       vstatus.state_table[(STATE_IDLE,MIFARE,1)] = handle_mifare_event
 
        vstatus.state_table[(STATE_DOOR_OPENING,TICK,1)] = handle_door_idle
        vstatus.state_table[(STATE_DOOR_OPENING,DOOR,1)] = handle_door_event
        vstatus.state_table[(STATE_DOOR_OPENING,KEY,1)] = do_nothing
+       vstatus.state_table[(STATE_DOOR_OPENING,MIFARE,1)] = do_nothing
 
        vstatus.state_table[(STATE_DOOR_CLOSING,TICK,1)] = return_to_idle
        vstatus.state_table[(STATE_DOOR_CLOSING,DOOR,1)] = handle_door_event
        vstatus.state_table[(STATE_DOOR_CLOSING,KEY,1)] = do_nothing
+       vstatus.state_table[(STATE_DOOR_CLOSING,MIFARE,1)] = do_nothing
 
        vstatus.state_table[(STATE_GETTING_UID,TICK,1)] = handle_getting_uid_idle
        vstatus.state_table[(STATE_GETTING_UID,DOOR,1)] = do_nothing
        vstatus.state_table[(STATE_GETTING_UID,KEY,1)] = handle_getting_uid_key
+       vstatus.state_table[(STATE_GETTING_UID,MIFARE,1)] = handle_mifare_event
 
        vstatus.state_table[(STATE_GETTING_PIN,TICK,1)] = handle_getting_pin_idle
        vstatus.state_table[(STATE_GETTING_PIN,DOOR,1)] = do_nothing
        vstatus.state_table[(STATE_GETTING_PIN,KEY,1)] = handle_getting_pin_key
+       vstatus.state_table[(STATE_GETTING_PIN,MIFARE,1)] = handle_mifare_event
 
        vstatus.state_table[(STATE_GET_SELECTION,TICK,1)] = handle_get_selection_idle
        vstatus.state_table[(STATE_GET_SELECTION,DOOR,1)] = do_nothing
        vstatus.state_table[(STATE_GET_SELECTION,KEY,1)] = handle_get_selection_key
+       vstatus.state_table[(STATE_GET_SELECTION,MIFARE,1)] = handle_mifare_add_user_event
 
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,TICK,1)] = handle_idle_grandfather_tick
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,TICK,2)] = handle_grandfather_tick
@@ -664,12 +930,21 @@ def create_state_table(vstatus):
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,DOOR,2)] = do_nothing
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,KEY,1)] = do_nothing
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,KEY,2)] = do_nothing
+       vstatus.state_table[(STATE_GRANDFATHER_CLOCK,MIFARE,1)] = handle_mifare_event
 
 def get_state_table_handler(vstatus, state, event, counter):
        return vstatus.state_table[(state,event,counter)]
 
+def time_to_next_update(vstatus):
+       idle_update = vstatus.time_of_next_idlestep - time()
+       if not vstatus.mk.done() and vstatus.mk.next_update is not None:
+               mk_update = vstatus.mk.next_update - time()
+               if mk_update < idle_update:
+                       idle_update = mk_update
+       return idle_update
+
 def run_forever(rfh, wfh, options, cf):
-       v = VendingMachine(rfh, wfh)
+       v = VendingMachine(rfh, wfh, USE_MIFARE)
        vstatus = VendState(v)
        create_state_table(vstatus)
 
@@ -698,8 +973,8 @@ def run_forever(rfh, wfh, options, cf):
                        except DispenseDatabaseException, e:
                                logging.error('Database error: '+str(e))
 
-
-               e = v.next_event(vstatus.time_of_next_idlestep-time())
+               timeout = time_to_next_update(vstatus)
+               e = v.next_event(timeout)
                (event, params) = e
 
                run_handler(event, params, v, vstatus)
@@ -731,6 +1006,8 @@ def connect_to_vend(options, cf):
                sock.connect((options.host, options.port))
                rfh = sock.makefile('r')
                wfh = sock.makefile('w')
+               global USE_MIFARE
+               USE_MIFARE = 0
                
        return rfh, wfh
 
@@ -738,7 +1015,7 @@ def parse_args():
        from optparse import OptionParser
 
        op = OptionParser(usage="%prog [OPTION]...")
-       op.add_option('-f', '--config-file', default='/etc/dispense/servers.conf', metavar='FILE', dest='config_file', help='use the specified config file instead of /etc/dispense/servers.conf')
+       op.add_option('-f', '--config-file', default='/etc/dispense2/servers.conf', metavar='FILE', dest='config_file', help='use the specified config file instead of /etc/dispense/servers.conf')
        op.add_option('--serial', action='store_true', default=True, dest='use_serial', help='use the serial port')
        op.add_option('--lat', action='store_true', default=False, dest='use_lat', help='use LAT')
        op.add_option('--virtualvend', action='store_false', default=True, dest='use_serial', help='use the virtual vending server instead of LAT')
@@ -869,6 +1146,8 @@ def do_vend_server(options, config_opts):
                        sleep(5)
                        continue
                
+#              run_forever(rfh, wfh, options, config_opts)
+               
                try:
                        run_forever(rfh, wfh, options, config_opts)
                except VendingException:

UCC git Repository :: git.ucc.asn.au