From bebd1393c36f360b0a5e16289d699f02369f61fd Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Sun, 1 Mar 2015 23:00:00 +0800 Subject: [PATCH 01/16] Fixed init script not working correctly --- bin/init.d/vendserver | 58 ++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/bin/init.d/vendserver b/bin/init.d/vendserver index 3390401..438bbf7 100755 --- a/bin/init.d/vendserver +++ b/bin/init.d/vendserver @@ -19,43 +19,45 @@ PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME DAEMON_ARGS="" -# Gracefully exit if the package has been removed. -test -x $DAEMON || exit 0 +# Say something and gracefully exit if the package has been removed. +if ! test -x $DAEMON; then + echo "Failed to find the executable $DAEMON" + exit 1 +fi + d_start() { - start-stop-daemon --start --quiet --pidfile $PIDFILE \ - --nicelevel 5 \ - --exec $DAEMON -- -d -sdaemon --pid-file=$PIDFILE \ + start-stop-daemon --start --pidfile $PIDFILE --nicelevel 5 \ + --startas $DAEMON -- -d -sdaemon --pid-file=$PIDFILE \ $DAEMON_ARGS } d_stop() { - start-stop-daemon --stop --quiet --pidfile $PIDFILE \ - --name $NAME + start-stop-daemon --stop --pidfile $PIDFILE } case "$1" in - start) - echo -n "Starting $DESC: $NAME" - d_start - echo "." - ;; - stop) - echo -n "Stopping $DESC: $NAME" - d_stop - echo "." - ;; - restart|force-reload) - echo -n "Restarting $DESC: $NAME" - d_stop - sleep 1 - d_start - echo "." - ;; - *) - echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 - exit 1 - ;; + start) + echo -n "Starting $DESC: $NAME\n" + d_start + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME\n" + d_stop + echo "." + ;; + restart|force-reload) + echo -n "Restarting $DESC: $NAME\n" + d_stop + sleep 1 + d_start + echo "." + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 + exit 1 + ;; esac exit 0 -- 2.20.1 From 33c571c78669c60bf4be3cff2f02278510497b13 Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Mon, 2 Mar 2015 21:52:31 +0800 Subject: [PATCH 02/16] MIFARE Reader only triggers once unless a new card is used --- VendServer/VendServer.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/VendServer/VendServer.py b/VendServer/VendServer.py index ef74c0d..8fbf11e 100755 --- a/VendServer/VendServer.py +++ b/VendServer/VendServer.py @@ -390,6 +390,7 @@ def handle_getting_pin_idle(state, event, params, v, vstatus): pass def handle_get_selection_idle(state, event, params, v, vstatus): + global _last_card_id # don't care right now. ### ### State logging out .. @@ -405,7 +406,7 @@ def handle_get_selection_idle(state, event, params, v, vstatus): vstatus.cur_user = '' vstatus.cur_pin = '' vstatus.cur_selection = '' - + _last_card_id = -1 reset_idler(v, vstatus) ### State fully logged out ... reset variables @@ -427,13 +428,14 @@ def handle_get_selection_idle(state, event, params, v, vstatus): def handle_get_selection_key(state, event, params, v, vstatus): + global _last_card_id key = params if len(vstatus.cur_selection) == 0: if key == 11: vstatus.cur_pin = '' vstatus.cur_user = '' vstatus.cur_selection = '' - + _last_card_id = -1 vstatus.mk.set_messages([(center('BYE!'), False, 1.5)]) reset_idler(v, vstatus, 2) return @@ -842,12 +844,17 @@ def handle_door_event(state, event, params, v, vstatus): logging.warning('Leaving open door mode') v.display("-YUM YUM!-") +_last_card_id = -1 + def handle_mifare_event(state, event, params, v, vstatus): + global _last_card_id card_id = params # Translate card_id into uid. - if card_id == None: + if card_id == None or card_id == _last_card_id: return + _last_card_id = card_id + try: vstatus.cur_user = get_uid(card_id) logging.info('Mapped card id to uid %s'%vstatus.cur_user) @@ -885,12 +892,15 @@ def handle_mifare_event(state, event, params, v, vstatus): return def handle_mifare_add_user_event(state, event, params, v, vstatus): - card_id = params + global _last_card_id + card_id = params # Translate card_id into uid. - if card_id == None: + if card_id == None or card_id == _last_card_id: return + _last_card_id = card_id + try: if get_uid(card_id) != None: vstatus.mk.set_messages( -- 2.20.1 From 2a6c4f6e2a5697341f5ea7f22f36d7761870e10f Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Wed, 4 Mar 2015 14:34:00 +0800 Subject: [PATCH 03/16] Fix bug were cards read before logging in cannot be read until a logout occurs --- VendServer/VendServer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/VendServer/VendServer.py b/VendServer/VendServer.py index 8fbf11e..c16cff1 100755 --- a/VendServer/VendServer.py +++ b/VendServer/VendServer.py @@ -887,6 +887,7 @@ def handle_mifare_event(state, event, params, v, vstatus): (center('SORRY'), False, 0.5)]) vstatus.cur_user = '' vstatus.cur_pin = '' + _last_card_id = -1 reset_idler(v, vstatus, 2) return -- 2.20.1 From fc54224064166688cff70891381774884d5c7729 Mon Sep 17 00:00:00 2001 From: Mark Tearle Date: Sat, 7 Mar 2015 21:20:10 +0800 Subject: [PATCH 04/16] Add entrypoint to setup.py for vendserver --- VendServer/VendServer.py | 5 ++++- bin/init.d/vendserver | 2 +- setup.py | 5 +++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/VendServer/VendServer.py b/VendServer/VendServer.py index c16cff1..d079b4e 100755 --- a/VendServer/VendServer.py +++ b/VendServer/VendServer.py @@ -1186,7 +1186,8 @@ def do_vend_server(options, config_opts): logging.info("Trying again in 5 seconds.") sleep(5) -if __name__ == '__main__': + +def main(argv=None): options, config_opts = set_stuff_up() while True: try: @@ -1216,3 +1217,5 @@ if __name__ == '__main__': sleep(10) logging.warning("Trying again anyway (might not help, but hey...)") +if __name__ == '__main__': + sys.exit(main()) diff --git a/bin/init.d/vendserver b/bin/init.d/vendserver index 438bbf7..6ae51ab 100755 --- a/bin/init.d/vendserver +++ b/bin/init.d/vendserver @@ -14,7 +14,7 @@ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/games DESC="VendServer" NAME=vendserver -DAEMON="/usr/local/uccvend-vendserver/VendServer/VendServer.py" +DAEMON="/usr/local/uccvend-vendserver/vendserver" PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME DAEMON_ARGS="" diff --git a/setup.py b/setup.py index 9611d59..a17fbdc 100755 --- a/setup.py +++ b/setup.py @@ -40,6 +40,11 @@ setup( ] ) ], + entry_points={ + "console_scripts": [ + "vendserver = VendServer.VendServer:main" + ] + }, include_package_data=True, install_requires=requirements, license="BSD", -- 2.20.1 From ed50c28e02f4be810b2a492717904ec8cd5a4970 Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Sun, 8 Mar 2015 22:54:43 +0800 Subject: [PATCH 05/16] DispenseInterface and OpenDispense Implimentation created and tested. Not curruntly used by VendServer --- VendServer/DispenseInterface.py | 70 +++++++++++++++ VendServer/OpenDispense.py | 126 +++++++++++++++++++++++++++ VendServer/OpenDispenseMappings.conf | 76 ++++++++++++++++ 3 files changed, 272 insertions(+) create mode 100644 VendServer/DispenseInterface.py create mode 100644 VendServer/OpenDispense.py create mode 100644 VendServer/OpenDispenseMappings.conf diff --git a/VendServer/DispenseInterface.py b/VendServer/DispenseInterface.py new file mode 100644 index 0000000..81a3f06 --- /dev/null +++ b/VendServer/DispenseInterface.py @@ -0,0 +1,70 @@ +""" +Author: Mitchell Pomery (bobgeorge33) + +Dispense is an abstract class that allows easy configuration between different systems. Anything that is +intended to talk to OpenDispense or similar should comply with this class. Using this class in particular +will cause you a lot of problems. +""" + +class DispenseInterface(object): + + """ + Create a new dispense object. + """ + def __init__(self, username=None, loggedIn=False, disabled=False): + pass + + """ + Create a new dispense interface as the supplied user. + """ + @staticmethod + def authUsernamePin(username, pin): + pass + + """ + Create a new dispense interface as the supplied user. + """ + @staticmethod + def authMifare(cardId): + pass + + """ + Check if creating the user worked correctly. + """ + def isLoggedIn(self): + pass + + """ + Get the users username. + """ + def getUsername(self, user): + pass + + """ + Get the users current balance. + """ + def getBalance(self, user): + pass + + """ + Get the name and price of an item. + itemId is the number entered into the vending machine + """ + @staticmethod + def getItemInfo(itemId): + pass + + """ + Check if the user is disabled. + """ + def isDisabled(self): + pass + + """ + Dispense an item for the current user. + itemId is the number entered into the vending machine + """ + def dispenseItem(self, itemId): + pass + + diff --git a/VendServer/OpenDispense.py b/VendServer/OpenDispense.py new file mode 100644 index 0000000..f8cee0d --- /dev/null +++ b/VendServer/OpenDispense.py @@ -0,0 +1,126 @@ +from DispenseInterface import DispenseInterface +import os +import re +import pwd +from subprocess import Popen, PIPE +from LDAPConnector import get_uid,get_uname, set_card_id + +""" +Author: Mitchell Pomery (bobgeorge33) + +System to connect to OpenDispense2. +Most of this code has been copied out of VendServer.py, then had variables updated so that it runs. +This is so VendServer can easily operate regardless of the current accounting backend. +Documentation for this code can be found inder Dispence.DispenceInterface +""" +class OpenDispense(DispenseInterface): + _username = None + _disabled = True + _loggedIn = False + _userId = None + + def __init__(self, userId=None, username=None, loggedIn=False): + self._username = username + self._loggedIn = loggedIn + self._userId = userId + + acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate() + # this is fucking appalling + flags = acct[acct.find("(")+1:acct.find(")")].strip() + if 'disabled' in flags: + self._disabled = True + if 'internal' in flags: + self._disabled = True + self._disabled = False + + @staticmethod + def authUserIdPin(userId, pin): + try: + # Get info from + info = pwd.getpwuid(userId) + 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().strip() + f.close() + if not re.search('^[0-9]{4}$', pinstr): + logging.info('getting pin for uid %d: %s not a good pin'%(uid,repr(pinstr))) + return None + return OpenDispense(userId, info.pw_name, (int(pin)==int(pinstr))) + + @staticmethod + def authMifareCard(cardId): + return OpenDispense(get_uid(cardId), get_uname(get_uid(cardId)), True) + + def addCard(self, cardId): + set_card_id(self._userId, cardId) + + def isLoggedIn(self): + return self._loggedIn + + def getUsername(self): + return self._username + + def getBalance(self): + # Balance checking + acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate() + # this is fucking appalling + balance = acct[acct.find("$")+1:acct.find("(")].strip() + return balance + + def getItemInfo(itemId): + itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId) + args = ('dispense', 'iteminfo', itemId) + 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)) + # return (name, price in cents) + return (m.group(3), cents) + + def isDisabled(self): + return False + + def dispenseItem(self, itemId): + itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId) + if itemId == "": + return False + else: + print('dispense -u "%s" %s'%(self._username, itemId)) + os.system('dispense -u "%s" %s'%(self._username, itemId)) + return True + +""" +This class abstracts the idea of item numbers. +It removes the need for VendServer to know the mappings between inputted numbers +and the equivalent itemId in OpenDispense. +""" +class OpenDispenseMapping(): + + @staticmethod + def vendingMachineToOpenDispense(itemId): + _mappingFile = "OpenDispenseMappings.conf" + fh = open(_mappingFile) + map = "" + for line in fh: + #line = line.strip() + if line.startswith(str(itemId) + " "): + map = line[len(str(itemId)) + 1:].strip() + print(map) + return map + diff --git a/VendServer/OpenDispenseMappings.conf b/VendServer/OpenDispenseMappings.conf new file mode 100644 index 0000000..61485ca --- /dev/null +++ b/VendServer/OpenDispenseMappings.conf @@ -0,0 +1,76 @@ +# This file is used to map things from vending machine inputs into OpenDispense items +# Lines that start with a # are comments +# Lines that contain only white space are ignored + +# The top three rows only contain 5 slots for items + +11 snack:11 +31 snack:31 +51 snack:51 +71 snack:71 +91 snack:91 + +12 snack:12 +32 snack:32 +52 snack:52 +72 snack:72 +92 snack:92 + +13 snack:13 +33 snack:33 +53 snack:53 +73 snack:73 +93 snack:93 + +# This row has 10 + +04 snack:04 +14 snack:14 +24 snack:24 +34 snack:34 +44 snack:44 +54 snack:54 +64 snack:64 +74 snack:74 +84 snack:84 +94 snack:94 + +# Row 5 is used only for door + +55 door + +# The next two rows have 10 items each + +06 snack:06 +16 snack:16 +26 snack:26 +36 snack:36 +46 snack:46 +56 snack:56 +66 snack:66 +76 snack:76 +86 snack:86 +96 snack:96 + +07 snack:07 +17 snack:17 +27 snack:27 +37 snack:37 +47 snack:47 +57 snack:57 +67 snack:67 +77 snack:77 +87 snack:87 +97 snack:97 + +# This last lot is for coke + +08 coke:0 +18 coke:1 +28 coke:2 +38 coke:3 +48 coke:4 +58 coke:5 +68 coke:6 + +# There is no row 9 -- 2.20.1 From 9e8e3882ecbac2aca8d9eb31c9bc833057778a5b Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Sun, 8 Mar 2015 23:11:54 +0800 Subject: [PATCH 06/16] Added addCard to DispenseInterface --- VendServer/DispenseInterface.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/VendServer/DispenseInterface.py b/VendServer/DispenseInterface.py index 81a3f06..7af3653 100644 --- a/VendServer/DispenseInterface.py +++ b/VendServer/DispenseInterface.py @@ -28,6 +28,12 @@ class DispenseInterface(object): def authMifare(cardId): pass + """ + Add a MIFARE card for this user + """ + def addCard(self, cardId): + pass + """ Check if creating the user worked correctly. """ -- 2.20.1 From 3dbb7110b80053c2d65434984a32194a4d30fa13 Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Sun, 8 Mar 2015 23:16:11 +0800 Subject: [PATCH 07/16] Rearrange File Slightly --- VendServer/VendServer.py | 83 +++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/VendServer/VendServer.py b/VendServer/VendServer.py index d079b4e..4eb2986 100755 --- a/VendServer/VendServer.py +++ b/VendServer/VendServer.py @@ -22,6 +22,7 @@ from SnackConfig import get_snack#, get_snacks import socket from posix import geteuid from LDAPConnector import get_uid,get_uname, set_card_id +from OpenDispense import OpenDispense as Dispense CREDITS=""" This vending machine software brought to you by: @@ -65,6 +66,16 @@ STATE_GRANDFATHER_CLOCK, TEXT_SPEED = 0.8 IDLE_SPEED = 0.05 +_pin_uid = 0 +_pin_uname = 'root' +_pin_pin = '----' + +_last_card_id = -1 + +idlers = [] +idler = None + + class DispenseDatabaseException(Exception): pass class DispenseDatabase: @@ -96,6 +107,38 @@ class DispenseDatabase: self.process_requests() notify = self.db.getnotify() +class VendState: + def __init__(self,v): + self.state_table = {} + self.state = STATE_IDLE + self.counter = 0 + + self.mk = MessageKeeper(v) + self.cur_user = '' + self.cur_pin = '' + self.username = '' + self.cur_selection = '' + self.time_to_autologout = None + + self.last_timeout_refresh = None + + def change_state(self,newstate,newcounter=None): + if self.state != newstate: + #print "Changing state from: ", + #print self.state, + #print " to ", + #print newstate + self.state = newstate + + if newcounter is not None and self.counter != newcounter: + #print "Changing counter from: ", + #print self.counter, + #print " to ", + #print newcounter + self.counter = newcounter + + + def scroll_options(username, mk, welcome = False): if welcome: # Balance checking @@ -142,10 +185,6 @@ def scroll_options(username, mk, welcome = False): msg.append((choices, False, None)) mk.set_messages(msg) -_pin_uid = 0 -_pin_uname = 'root' -_pin_pin = '----' - def _check_pin(uid, pin): global _pin_uid global _pin_uname @@ -248,11 +287,6 @@ def center(str): LEN = 10 return ' '*((LEN-len(str))/2)+str - - -idlers = [] -idler = None - def setup_idlers(v): global idlers, idler idlers = [ @@ -336,36 +370,6 @@ def idle_step(vstatus): nextidle = IDLE_SPEED vstatus.time_of_next_idlestep = time()+nextidle -class VendState: - def __init__(self,v): - self.state_table = {} - self.state = STATE_IDLE - self.counter = 0 - - self.mk = MessageKeeper(v) - self.cur_user = '' - self.cur_pin = '' - self.username = '' - self.cur_selection = '' - self.time_to_autologout = None - - self.last_timeout_refresh = None - - def change_state(self,newstate,newcounter=None): - if self.state != newstate: - #print "Changing state from: ", - #print self.state, - #print " to ", - #print newstate - self.state = newstate - - if newcounter is not None and self.counter != newcounter: - #print "Changing counter from: ", - #print self.counter, - #print " to ", - #print newcounter - self.counter = newcounter - def handle_tick_event(event, params, v, vstatus): @@ -844,7 +848,6 @@ def handle_door_event(state, event, params, v, vstatus): logging.warning('Leaving open door mode') v.display("-YUM YUM!-") -_last_card_id = -1 def handle_mifare_event(state, event, params, v, vstatus): global _last_card_id -- 2.20.1 From 060a73740d793c8f1643554829c90a0dd442ca79 Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Sun, 8 Mar 2015 23:44:19 +0800 Subject: [PATCH 08/16] Rearranging file and adding comments --- VendServer/VendServer.py | 209 ++++++++++++++++++++++++--------------- 1 file changed, 128 insertions(+), 81 deletions(-) diff --git a/VendServer/VendServer.py b/VendServer/VendServer.py index 4eb2986..860c1c8 100755 --- a/VendServer/VendServer.py +++ b/VendServer/VendServer.py @@ -75,6 +75,33 @@ _last_card_id = -1 idlers = [] idler = None +config_options = { + 'DBServer': ('Database', 'Server'), + 'DBName': ('Database', 'Name'), + 'DBUser': ('VendingMachine', 'DBUser'), + 'DBPassword': ('VendingMachine', 'DBPassword'), + + 'ServiceName': ('VendingMachine', 'ServiceName'), + 'ServicePassword': ('VendingMachine', 'Password'), + + 'ServerName': ('DecServer', 'Name'), + 'ConnectPassword': ('DecServer', 'ConnectPassword'), + 'PrivPassword': ('DecServer', 'PrivPassword'), + } + +class VendConfigFile: + def __init__(self, config_file, options): + try: + cp = ConfigParser.ConfigParser() + cp.read(config_file) + + for option in options: + section, name = options[option] + value = cp.get(section, name) + self.__dict__[option] = value + + except ConfigParser.Error, e: + raise SystemExit("Error reading config file "+config_file+": " + str(e)) class DispenseDatabaseException(Exception): pass @@ -106,7 +133,9 @@ class DispenseDatabase: while notifier is not None: self.process_requests() notify = self.db.getnotify() - +""" +This class manages the current state of the vending machine. +""" class VendState: def __init__(self,v): self.state_table = {} @@ -124,22 +153,16 @@ class VendState: def change_state(self,newstate,newcounter=None): if self.state != newstate: - #print "Changing state from: ", - #print self.state, - #print " to ", - #print newstate self.state = newstate if newcounter is not None and self.counter != newcounter: - #print "Changing counter from: ", - #print self.counter, - #print " to ", - #print newcounter self.counter = newcounter - - +""" +Show information to the user as to what can be dispensed. +""" def scroll_options(username, mk, welcome = False): + # If the user has just logged in, show them their balance if welcome: # Balance checking acct, unused = Popen(['dispense', 'acct', username], close_fds=True, stdout=PIPE).communicate() @@ -153,7 +176,7 @@ def scroll_options(username, mk, welcome = False): msg = [] choices = ' '*10+'CHOICES: ' - # Get coke contents + # Show what is in the coke machine cokes = [] for i in range(0, 7): args = ('dispense', 'iteminfo', 'coke:%i' % i) @@ -168,23 +191,19 @@ def scroll_options(username, mk, welcome = False): if slot_name == 'dead': continue 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 ) - + # Show the final few options choices += '55-DOOR ' choices += 'OR ANOTHER SNACK. ' choices += '99 TO READ AGAIN. ' choices += 'CHOICE? ' msg.append((choices, False, None)) + # Send it to the display mk.set_messages(msg) + +""" +Verify the users pin +""" def _check_pin(uid, pin): global _pin_uid global _pin_uname @@ -227,6 +246,9 @@ def _check_pin(uid, pin): logging.info("Pin incorrect for %d",uid) return pin == int(pinstr) +""" +Check if the users account has been disabled +""" def acct_is_disabled(name=None): global _pin_uname if name == None: @@ -240,9 +262,15 @@ def acct_is_disabled(name=None): return True return False +""" +Check that the user has a valid pin set +""" def has_good_pin(uid): return _check_pin(uid, None) != None +""" +Verify the users 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) @@ -258,7 +286,9 @@ def verify_user_pin(uid, pin, skip_pin_check=False): logging.info('refused pin for uid %d'%(uid)) return None - +""" +In here just for fun. +""" def cookie(v): seed(time()) messages = [' WASSUP! ', 'PINK FISH ', ' SECRETS ', ' ESKIMO ', ' FORTUNES ', 'MORE MONEY'] @@ -283,10 +313,16 @@ def cookie(v): s += msg[i] v.display(s) +""" +Format text so it will appear centered on the screen. +""" def center(str): LEN = 10 return ' '*((LEN-len(str))/2)+str +""" +Configure the things that will appear on screen whil the machine is idling. +""" def setup_idlers(v): global idlers, idler idlers = [ @@ -322,6 +358,9 @@ def setup_idlers(v): disabled = [ ] +""" +Go back to the default idler. +""" def reset_idler(v, vstatus, t = None): global idlers, idler idler = GreetingIdler(v, t) @@ -330,6 +369,9 @@ def reset_idler(v, vstatus, t = None): vstatus.time_to_autologout = None vstatus.change_state(STATE_IDLE, 1) +""" +Change to a random idler. +""" def choose_idler(): global idlers, idler @@ -359,7 +401,9 @@ def choose_idler(): if idler: idler.reset() - +""" +Run every step while the machine is idling. +""" def idle_step(vstatus): global idler if idler.finished(): @@ -370,8 +414,9 @@ def idle_step(vstatus): nextidle = IDLE_SPEED vstatus.time_of_next_idlestep = time()+nextidle - - +""" +These next two events trigger no response in the code. +""" def handle_tick_event(event, params, v, vstatus): # don't care right now. pass @@ -380,11 +425,16 @@ def handle_switch_event(event, params, v, vstatus): # don't care right now. pass - +""" +Don't do anything for this event. +""" def do_nothing(state, event, params, v, vstatus): print "doing nothing (s,e,p)", state, " ", event, " ", params pass +""" +These next few entrie tell us to do nothing while we are idling +""" def handle_getting_uid_idle(state, event, params, v, vstatus): # don't care right now. pass @@ -393,6 +443,9 @@ def handle_getting_pin_idle(state, event, params, v, vstatus): # don't care right now. pass +""" +While logged in and waiting for user input, slowly get closer to logging out. +""" def handle_get_selection_idle(state, event, params, v, vstatus): global _last_card_id # don't care right now. @@ -429,8 +482,9 @@ def handle_get_selection_idle(state, event, params, v, vstatus): # need to check vstatus.mk.update_display() - - +""" +Triggered on user input while logged in. +""" def handle_get_selection_key(state, event, params, v, vstatus): global _last_card_id key = params @@ -466,13 +520,15 @@ def handle_get_selection_key(state, event, params, v, vstatus): vstatus.time_to_autologout = None vstatus.last_timeout_refresh = None +""" +Triggered when the user has entered the id of something they would like to purchase. +""" def make_selection(v, vstatus): # should use sudo here if vstatus.cur_selection == '55': 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('dispense -u "%s" door'%vstatus.username) else: ret = os.system('dispense door') @@ -503,8 +559,6 @@ def make_selection(v, vstatus): 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 @@ -526,7 +580,9 @@ def make_selection(v, vstatus): v.display('UNK ERROR') sleep(1) - +""" +Find the price of an item. +""" def price_check(v, vstatus): if vstatus.cur_selection[1] == '8': args = ('dispense', 'iteminfo', 'coke:' + vstatus.cur_selection[0]) @@ -541,7 +597,9 @@ def price_check(v, vstatus): dollarprice = "$%.2f" % ( price / 100.0 ) v.display(vstatus.cur_selection+' - %s'%dollarprice) - +""" +Triggered when the user presses a button while entering their pin. +""" def handle_getting_pin_key(state, event, params, v, vstatus): #print "handle_getting_pin_key (s,e,p)", state, " ", event, " ", params key = params @@ -577,7 +635,9 @@ def handle_getting_pin_key(state, event, params, v, vstatus): return - +""" +Triggered when the user presses a button while entering their user id. +""" def handle_getting_uid_key(state, event, params, v, vstatus): #print "handle_getting_uid_key (s,e,p)", state, " ", event, " ", params key = params @@ -677,7 +737,9 @@ Wouldn't you prefer a nice game of chess? vstatus.change_state(STATE_GETTING_PIN) return - +""" +Triggered when a key is pressed and the machine is idling. +""" def handle_idle_key(state, event, params, v, vstatus): #print "handle_idle_key (s,e,p)", state, " ", event, " ", params @@ -691,7 +753,9 @@ def handle_idle_key(state, event, params, v, vstatus): vstatus.change_state(STATE_GETTING_UID) run_handler(event, key, v, vstatus) - +""" +What to do when there is nothing to do. +""" def handle_idle_tick(state, event, params, v, vstatus): ### State idling if vstatus.mk.done(): @@ -709,6 +773,9 @@ def handle_idle_tick(state, event, params, v, vstatus): run_handler(event, params, v, vstatus) sleep(0.05) +""" +Manages the beeps for the grandfather clock +""" def beep_on(when, before=0): start = int(when - before) end = int(when) @@ -813,6 +880,9 @@ def handle_grandfather_tick(state, event, params, v, vstatus): if go_idle and vstatus.mk.done(): vstatus.change_state(STATE_IDLE,1) +""" +What to do when the door is open. +""" def handle_door_idle(state, event, params, v, vstatus): def twiddle(clock,v,wise = 2): if (clock % 4 == 0): @@ -832,7 +902,9 @@ def handle_door_idle(state, event, params, v, vstatus): else: twiddle(now, v, wise=0) - +""" +What to do when the door is opened or closed. +""" def handle_door_event(state, event, params, v, vstatus): if params == 0: #door open vstatus.change_state(STATE_DOOR_OPENING) @@ -848,7 +920,9 @@ def handle_door_event(state, event, params, v, vstatus): logging.warning('Leaving open door mode') v.display("-YUM YUM!-") - +""" +Triggered when a user swipes their caed, and the machine is logged out. +""" def handle_mifare_event(state, event, params, v, vstatus): global _last_card_id card_id = params @@ -895,6 +969,9 @@ def handle_mifare_event(state, event, params, v, vstatus): reset_idler(v, vstatus, 2) return +""" +Triggered when a user swipes their card and the machine is logged in. +""" def handle_mifare_add_user_event(state, event, params, v, vstatus): global _last_card_id card_id = params @@ -927,6 +1004,9 @@ def handle_mifare_add_user_event(state, event, params, v, vstatus): def return_to_idle(state,event,params,v,vstatus): reset_idler(v, vstatus) +""" +Maps what to do when the state changes. +""" 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 @@ -966,6 +1046,9 @@ def create_state_table(vstatus): vstatus.state_table[(STATE_GRANDFATHER_CLOCK,KEY,2)] = do_nothing vstatus.state_table[(STATE_GRANDFATHER_CLOCK,MIFARE,1)] = handle_mifare_event +""" +Get what to do on a state change. +""" def get_state_table_handler(vstatus, state, event, counter): return vstatus.state_table[(state,event,counter)] @@ -989,17 +1072,6 @@ def run_forever(rfh, wfh, options, cf): setup_idlers(v) reset_idler(v, vstatus) - # This main loop was hideous and the work of the devil. - # This has now been fixed (mostly) - mtearle - # - # - # notes for later surgery - # (event, counter, ' ') - # V - # d[ ] = (method) - # - # ( return state - not currently implemented ) - while True: if USE_DB: try: @@ -1013,14 +1085,14 @@ def run_forever(rfh, wfh, options, cf): run_handler(event, params, v, vstatus) -# logging.debug('Got event: ' + repr(e)) - - def run_handler(event, params, v, vstatus): handler = get_state_table_handler(vstatus,vstatus.state,event,vstatus.counter) if handler: handler(vstatus.state, event, params, v, vstatus) +""" +Connect to the machine. +""" def connect_to_vend(options, cf): if options.use_lat: @@ -1045,6 +1117,9 @@ def connect_to_vend(options, cf): return rfh, wfh +""" +Parse arguments from the command line +""" def parse_args(): from optparse import OptionParser @@ -1068,34 +1143,6 @@ def parse_args(): return options -config_options = { - 'DBServer': ('Database', 'Server'), - 'DBName': ('Database', 'Name'), - 'DBUser': ('VendingMachine', 'DBUser'), - 'DBPassword': ('VendingMachine', 'DBPassword'), - - 'ServiceName': ('VendingMachine', 'ServiceName'), - 'ServicePassword': ('VendingMachine', 'Password'), - - 'ServerName': ('DecServer', 'Name'), - 'ConnectPassword': ('DecServer', 'ConnectPassword'), - 'PrivPassword': ('DecServer', 'PrivPassword'), - } - -class VendConfigFile: - def __init__(self, config_file, options): - try: - cp = ConfigParser.ConfigParser() - cp.read(config_file) - - for option in options: - section, name = options[option] - value = cp.get(section, name) - self.__dict__[option] = value - - except ConfigParser.Error, e: - raise SystemExit("Error reading config file "+config_file+": " + str(e)) - def create_pid_file(name): try: pid_file = file(name, 'w') -- 2.20.1 From 15173eaaa20442f08c2d32fca37825e5c3bcb3e6 Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Tue, 10 Mar 2015 21:50:33 +0800 Subject: [PATCH 09/16] Created VendServer Class --- VendServer/VendServer.py | 1753 +++++++++++++++++++------------------- 1 file changed, 870 insertions(+), 883 deletions(-) diff --git a/VendServer/VendServer.py b/VendServer/VendServer.py index 860c1c8..d6a07a0 100755 --- a/VendServer/VendServer.py +++ b/VendServer/VendServer.py @@ -66,14 +66,6 @@ STATE_GRANDFATHER_CLOCK, TEXT_SPEED = 0.8 IDLE_SPEED = 0.05 -_pin_uid = 0 -_pin_uname = 'root' -_pin_pin = '----' - -_last_card_id = -1 - -idlers = [] -idler = None config_options = { 'DBServer': ('Database', 'Server'), @@ -158,937 +150,931 @@ class VendState: if newcounter is not None and self.counter != newcounter: self.counter = newcounter -""" -Show information to the user as to what can be dispensed. -""" -def scroll_options(username, mk, welcome = False): - # If the user has just logged in, show them their balance - if welcome: - # Balance checking - acct, unused = Popen(['dispense', 'acct', username], close_fds=True, stdout=PIPE).communicate() +class VendServer(): + + v = None + vstatus = None + state = None + event = None + idlers = [] + idler = None + + _pin_uid = 0 + _pin_uname = 'root' + _pin_pin = '----' + _last_card_id = -1 + + """ + Show information to the user as to what can be dispensed. + """ + def scroll_options(self, username, mk, welcome = False): + # If the user has just logged in, show them their balance + 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 = [(self.center('WELCOME'), False, TEXT_SPEED), + (self.center(username), False, TEXT_SPEED), + (self.center(balance), False, TEXT_SPEED),] + else: + msg = [] + choices = ' '*10+'CHOICES: ' + + # Show what is in the coke machine + 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 += '%s-(%sc)-%s8 '%(slot_name, price, slot_num) + + # Show the final few options + choices += '55-DOOR ' + choices += 'OR ANOTHER SNACK. ' + choices += '99 TO READ AGAIN. ' + choices += 'CHOICE? ' + msg.append((choices, False, None)) + # Send it to the display + mk.set_messages(msg) + + + """ + Verify the users pin + """ + def _check_pin(self, uid, pin): + print "_check_pin('",uid,"',---)" + if uid != self._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 + self._pin_uid = uid + self._pin_pin = pinstr + self._pin_uname = info.pw_name + else: + pinstr = self._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) + + """ + Check if the users account has been disabled + """ + def acct_is_disabled(self, name=None): + if name == None: + name = self._pin_uname + acct, unused = Popen(['dispense', 'acct', self._pin_uname], 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(balance), False, TEXT_SPEED),] - else: - msg = [] - choices = ' '*10+'CHOICES: ' - - # Show what is in the coke machine - 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 += '%s-(%sc)-%s8 '%(slot_name, price, slot_num) - - # Show the final few options - choices += '55-DOOR ' - choices += 'OR ANOTHER SNACK. ' - choices += '99 TO READ AGAIN. ' - choices += 'CHOICE? ' - msg.append((choices, False, None)) - # Send it to the display - mk.set_messages(msg) - - -""" -Verify the users pin -""" -def _check_pin(uid, pin): - global _pin_uid - global _pin_uname - global _pin_pin - print "_check_pin('",uid,"',---)" - if uid != _pin_uid: - try: + flags = acct[acct.find("(")+1:acct.find(")")].strip() + if 'disabled' in flags: + return True + if 'internal' in flags: + return True + return False + + """ + Check that the user has a valid pin set + """ + def has_good_pin(self, uid): + return self._check_pin(uid, None) != None + + """ + Verify the users pin. + """ + def verify_user_pin(self, uid, pin, skip_pin_check=False): + if skip_pin_check or self._check_pin(uid, pin) == True: 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) - -""" -Check if the users account has been disabled -""" -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 - -""" -Check that the user has a valid pin set -""" -def has_good_pin(uid): - return _check_pin(uid, None) != None - -""" -Verify the users 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) - 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)) + if skip_pin_check: + if self.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('accepted pin for uid %d (%s)'%(uid,info.pw_name)) - return info.pw_name - else: - logging.info('refused pin for uid %d'%(uid)) - return None + logging.info('refused pin for uid %d'%(uid)) + return None -""" -In here just for fun. -""" -def cookie(v): - seed(time()) - messages = [' WASSUP! ', 'PINK FISH ', ' SECRETS ', ' ESKIMO ', ' FORTUNES ', 'MORE MONEY'] - choice = int(random()*len(messages)) - msg = messages[choice] - left = range(len(msg)) - for i in range(len(msg)): - if msg[i] == ' ': left.remove(i) - reveal = 1 - while left: - s = '' - for i in range(0, len(msg)): - if i in left: - if reveal == 0: - left.remove(i) - s += msg[i] + """ + In here just for fun. + """ + def cookie(self): + seed(time()) + messages = [' WASSUP! ', 'PINK FISH ', ' SECRETS ', ' ESKIMO ', ' FORTUNES ', 'MORE MONEY'] + choice = int(random()*len(messages)) + msg = messages[choice] + left = range(len(msg)) + for i in range(len(msg)): + if msg[i] == ' ': left.remove(i) + reveal = 1 + while left: + s = '' + for i in range(0, len(msg)): + if i in left: + if reveal == 0: + left.remove(i) + s += msg[i] + else: + s += chr(int(random()*26)+ord('A')) + reveal += 1 + reveal %= 17 else: - s += chr(int(random()*26)+ord('A')) - reveal += 1 - reveal %= 17 - else: - s += msg[i] - v.display(s) - -""" -Format text so it will appear centered on the screen. -""" -def center(str): - LEN = 10 - return ' '*((LEN-len(str))/2)+str - -""" -Configure the things that will appear on screen whil the machine is idling. -""" -def setup_idlers(v): - global idlers, idler - idlers = [ - # - GrayIdler(v), - GrayIdler(v,one="*",zero="-"), - GrayIdler(v,one="/",zero="\\"), - GrayIdler(v,one="X",zero="O"), - GrayIdler(v,one="*",zero="-",reorder=1), - GrayIdler(v,one="/",zero="\\",reorder=1), - GrayIdler(v,one="X",zero="O",reorder=1), - # - ClockIdler(v), - ClockIdler(v), - ClockIdler(v), - # - StringIdler(v), # Hello Cruel World - StringIdler(v, text="Kill 'em all", repeat=False), - StringIdler(v, text=CREDITS), - StringIdler(v, text=str(math.pi) + " "), - StringIdler(v, text=str(math.e) + " "), - StringIdler(v, text=" I want some pizza - please call Broadway Pizza on +61 8 9389 8500 - and order as Quinn - I am getting really hungry", repeat=False), - # "Hello World" in brainfuck - StringIdler(v, text=">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-] <.>+++++++++++[<++++++++>-]<-.--------.+++.------.--------.[-]>++++++++[<++++>- ]<+.[-]++++++++++."), - # - TrainIdler(v), - # - FileIdler(v, '/usr/share/common-licenses/GPL-2',affinity=2), - # - PipeIdler(v, "/usr/bin/getent", "passwd"), - FortuneIdler(v,affinity=20), - ] - disabled = [ - ] - -""" -Go back to the default idler. -""" -def reset_idler(v, vstatus, t = None): - global idlers, idler - 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) - -""" -Change to a random idler. -""" -def choose_idler(): - global idlers, idler - - # Implementation of the King Of the Hill algorithm from; - # http://eli.thegreenplace.net/2010/01/22/weighted-random-generation-in-python/ - - #def weighted_choice_king(weights): - # total = 0 - # winner = 0 - # for i, w in enumerate(weights): - # total += w - # if random.random() * total < w: - # winner = i - # return winner - # - - total = 0 - winner = None - - for choice in idlers: - weight = choice.affinity() - total += weight - if random() * total < weight: - winner = choice - - idler = winner - - if idler: - idler.reset() -""" -Run every step while the machine is idling. -""" -def idle_step(vstatus): - global idler - if idler.finished(): - choose_idler() - vstatus.time_of_next_idler = time() + 30 - nextidle = idler.next() - if nextidle is None: - nextidle = IDLE_SPEED - vstatus.time_of_next_idlestep = time()+nextidle - -""" -These next two events trigger no response in the code. -""" -def handle_tick_event(event, params, v, vstatus): - # don't care right now. - pass - -def handle_switch_event(event, params, v, vstatus): - # don't care right now. - pass - -""" -Don't do anything for this event. -""" -def do_nothing(state, event, params, v, vstatus): - print "doing nothing (s,e,p)", state, " ", event, " ", params - pass + s += msg[i] + self.v.display(s) + + """ + Format text so it will appear centered on the screen. + """ + def center(self, str): + LEN = 10 + return ' '*((LEN-len(str))/2)+str + + """ + Configure the things that will appear on screen whil the machine is idling. + """ + def setup_idlers(self): + self.idlers = [ + # + GrayIdler(self.v), + GrayIdler(self.v,one="*",zero="-"), + GrayIdler(self.v,one="/",zero="\\"), + GrayIdler(self.v,one="X",zero="O"), + GrayIdler(self.v,one="*",zero="-",reorder=1), + GrayIdler(self.v,one="/",zero="\\",reorder=1), + GrayIdler(self.v,one="X",zero="O",reorder=1), + # + ClockIdler(self.v), + ClockIdler(self.v), + ClockIdler(self.v), + # + StringIdler(self.v), # Hello Cruel World + StringIdler(self.v, text="Kill 'em all", repeat=False), + StringIdler(self.v, text=CREDITS), + StringIdler(self.v, text=str(math.pi) + " "), + StringIdler(self.v, text=str(math.e) + " "), + StringIdler(self.v, text=" I want some pizza - please call Broadway Pizza on +61 8 9389 8500 - and order as Quinn - I am getting really hungry", repeat=False), + # "Hello World" in brainfuck + StringIdler(self.v, text=">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-] <.>+++++++++++[<++++++++>-]<-.--------.+++.------.--------.[-]>++++++++[<++++>- ]<+.[-]++++++++++."), + # + TrainIdler(self.v), + # + FileIdler(self.v, '/usr/share/common-licenses/GPL-2',affinity=2), + # + PipeIdler(self.v, "/usr/bin/getent", "passwd"), + FortuneIdler(self.v,affinity=20), + ] + disabled = [ + ] + + """ + Go back to the default idler. + """ + def reset_idler(self, t = None): + self.idler = GreetingIdler(self.v, t) + self.vstatus.time_of_next_idlestep = time()+self.idler.next() + self.vstatus.time_of_next_idler = None + self.vstatus.time_to_autologout = None + self.vstatus.change_state(STATE_IDLE, 1) + + """ + Change to a random idler. + """ + def choose_idler(self): + + # Implementation of the King Of the Hill algorithm from; + # http://eli.thegreenplace.net/2010/01/22/weighted-random-generation-in-python/ + + #def weighted_choice_king(weights): + # total = 0 + # winner = 0 + # for i, w in enumerate(weights): + # total += w + # if random.random() * total < w: + # winner = i + # return winner + # + + total = 0 + winner = None + + for choice in self.idlers: + weight = choice.affinity() + total += weight + if random() * total < weight: + winner = choice + + self.idler = winner + + if self.idler: + self.idler.reset() + """ + Run every step while the machine is idling. + """ + def idle_step(self): + if self.idler.finished(): + self.choose_idler() + self.vstatus.time_of_next_idler = time() + 30 + nextidle = self.idler.next() + if nextidle is None: + nextidle = IDLE_SPEED + self.vstatus.time_of_next_idlestep = time()+nextidle + + """ + These next two events trigger no response in the code. + """ + def handle_tick_event(self, event, params): + # don't care right now. + pass -""" -These next few entrie tell us to do nothing while we are idling -""" -def handle_getting_uid_idle(state, event, params, v, vstatus): - # don't care right now. - pass + def handle_switch_event(self, event, params): + # don't care right now. + pass -def handle_getting_pin_idle(state, event, params, v, vstatus): - # don't care right now. - pass + """ + Don't do anything for this event. + """ + def do_nothing(self, event, params): + print "doing nothing (s,e,p)", state, " ", event, " ", params + pass -""" -While logged in and waiting for user input, slowly get closer to logging out. -""" -def handle_get_selection_idle(state, event, params, v, vstatus): - global _last_card_id - # don't care right now. - ### - ### State logging out .. - if vstatus.time_to_autologout != None: - time_left = vstatus.time_to_autologout - time() - if time_left < 6 and (vstatus.last_timeout_refresh is None or vstatus.last_timeout_refresh > time_left): - vstatus.mk.set_message('LOGOUT: '+str(int(time_left))) - vstatus.last_timeout_refresh = int(time_left) - vstatus.cur_selection = '' - - if vstatus.time_to_autologout != None and vstatus.time_to_autologout - time() <= 0: - vstatus.time_to_autologout = None - vstatus.cur_user = '' - vstatus.cur_pin = '' - vstatus.cur_selection = '' - _last_card_id = -1 - reset_idler(v, vstatus) - - ### State fully logged out ... reset variables - if vstatus.time_to_autologout and not vstatus.mk.done(): - vstatus.time_to_autologout = None - if vstatus.cur_user == '' and vstatus.time_to_autologout: - vstatus.time_to_autologout = None - - ### State logged in - if len(vstatus.cur_pin) == PIN_LENGTH and vstatus.mk.done() and vstatus.time_to_autologout == None: - # start autologout - vstatus.time_to_autologout = time() + 15 - vstatus.last_timeout_refresh = None + """ + These next few entrie tell us to do nothing while we are idling + """ + def handle_getting_uid_idle(self, event, params): + # don't care right now. + pass - ## FIXME - this may need to be elsewhere..... - # need to check - vstatus.mk.update_display() + def handle_getting_pin_idle(self, event, params): + # don't care right now. + pass -""" -Triggered on user input while logged in. -""" -def handle_get_selection_key(state, event, params, v, vstatus): - global _last_card_id - key = params - if len(vstatus.cur_selection) == 0: - if key == 11: - vstatus.cur_pin = '' - vstatus.cur_user = '' - vstatus.cur_selection = '' - _last_card_id = -1 - 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) - vstatus.time_to_autologout = None - elif len(vstatus.cur_selection) == 1: - if key == 11: - vstatus.cur_selection = '' - vstatus.time_to_autologout = None - scroll_options(vstatus.username, vstatus.mk) + """ + While logged in and waiting for user input, slowly get closer to logging out. + """ + def handle_get_selection_idle(self, event, params): + # don't care right now. + ### + ### State logging out .. + if self.vstatus.time_to_autologout != None: + time_left = self.vstatus.time_to_autologout - time() + if time_left < 6 and (self.vstatus.last_timeout_refresh is None or self.vstatus.last_timeout_refresh > time_left): + self.vstatus.mk.set_message('LOGOUT: '+str(int(time_left))) + self.vstatus.last_timeout_refresh = int(time_left) + self.vstatus.cur_selection = '' + + if self.vstatus.time_to_autologout != None and self.vstatus.time_to_autologout - time() <= 0: + self.vstatus.time_to_autologout = None + self.vstatus.cur_user = '' + self.vstatus.cur_pin = '' + self.vstatus.cur_selection = '' + self._last_card_id = -1 + self.reset_idler() + + ### State fully logged out ... reset variables + if self.vstatus.time_to_autologout and not self.vstatus.mk.done(): + self.vstatus.time_to_autologout = None + if self.vstatus.cur_user == '' and self.vstatus.time_to_autologout: + self.vstatus.time_to_autologout = None + + ### State logged in + if len(self.vstatus.cur_pin) == PIN_LENGTH and self.vstatus.mk.done() and self.vstatus.time_to_autologout == None: + # start autologout + self.vstatus.time_to_autologout = time() + 15 + self.vstatus.last_timeout_refresh = None + + ## FIXME - this may need to be elsewhere..... + # need to check + self.vstatus.mk.update_display() + + """ + Triggered on user input while logged in. + """ + def handle_get_selection_key(self, event, params): + key = params + if len(self.vstatus.cur_selection) == 0: + if key == 11: + self.vstatus.cur_pin = '' + self.vstatus.cur_user = '' + self.vstatus.cur_selection = '' + _last_card_id = -1 + self.vstatus.mk.set_messages([(self.center('BYE!'), False, 1.5)]) + self.reset_idler(2) + return + self.vstatus.cur_selection += chr(key + ord('0')) + self.vstatus.mk.set_message('SELECT: '+self.vstatus.cur_selection) + self.vstatus.time_to_autologout = None + elif len(self.vstatus.cur_selection) == 1: + if key == 11: + self.vstatus.cur_selection = '' + self.vstatus.time_to_autologout = None + self.scroll_options(self.vstatus.username, self.vstatus.mk) + return + else: + self.vstatus.cur_selection += chr(key + ord('0')) + if self.vstatus.cur_user: + self.make_selection() + self.vstatus.cur_selection = '' + self.vstatus.time_to_autologout = time() + 8 + self.vstatus.last_timeout_refresh = None + else: + # Price check mode. + self.price_check() + self.vstatus.cur_selection = '' + self.vstatus.time_to_autologout = None + self.vstatus.last_timeout_refresh = None + + """ + Triggered when the user has entered the id of something they would like to purchase. + """ + def make_selection(self): + # should use sudo here + if self.vstatus.cur_selection == '55': + self.vstatus.mk.set_message('OPENSESAME') + logging.info('dispensing a door for %s'%self.vstatus.username) + if geteuid() == 0: + ret = os.system('dispense -u "%s" door'%self.vstatus.username) + else: + ret = os.system('dispense door') + if ret == 0: + logging.info('door opened') + self.vstatus.mk.set_message(self.center('DOOR OPEN')) + else: + logging.warning('user %s tried to dispense a bad door'%self.vstatus.username) + self.vstatus.mk.set_message(self.center('BAD DOOR')) + sleep(1) + elif self.vstatus.cur_selection == '81': + self.cookie() + elif self.vstatus.cur_selection == '99': + self.scroll_options(self.vstatus.username, self.vstatus.mk) + self.vstatus.cur_selection = '' return - else: - vstatus.cur_selection += chr(key + ord('0')) - if vstatus.cur_user: - make_selection(v,vstatus) - vstatus.cur_selection = '' - vstatus.time_to_autologout = time() + 8 - vstatus.last_timeout_refresh = None + elif self.vstatus.cur_selection[1] == '8': + self.v.display('GOT DRINK?') + if ((os.system('dispense -u "%s" coke:%s'%(self.vstatus.username, self.vstatus.cur_selection[0])) >> 8) != 0): + self.v.display('SEEMS NOT') else: - # Price check mode. - price_check(v,vstatus) - vstatus.cur_selection = '' - vstatus.time_to_autologout = None - vstatus.last_timeout_refresh = None - -""" -Triggered when the user has entered the id of something they would like to purchase. -""" -def make_selection(v, vstatus): - # should use sudo here - if vstatus.cur_selection == '55': - vstatus.mk.set_message('OPENSESAME') - logging.info('dispensing a door for %s'%vstatus.username) - if geteuid() == 0: - ret = os.system('dispense -u "%s" door'%vstatus.username) - else: - ret = os.system('dispense door') - if ret == 0: - logging.info('door opened') - vstatus.mk.set_message(center('DOOR OPEN')) + self.v.display('GOT DRINK!') else: - 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 == '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 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 DRINK!') - 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" 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') + # first see if it's a named slot + try: + price, shortname, name = get_snack( self.vstatus.cur_selection ) + except: + price, shortname, name = get_snack( '--' ) + dollarprice = "$%.2f" % ( price / 100.0 ) + self.v.display(self.vstatus.cur_selection+' - %s'%dollarprice) + exitcode = os.system('dispense -u "%s" snack:%s'%(self.vstatus.username, self.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, self.vstatus.cur_selection, self.vstatus.username)) + (worked, code, string) = self.v.vend(self.vstatus.cur_selection) + if worked: + self.v.display('THANK YOU') + else: + print "Vend Failed:", code, string + self.v.display('VEND FAIL') + elif (exitcode == 5): # RV_BALANCE + self.v.display('NO MONEY?') + elif (exitcode == 4): # RV_ARGUMENTS (zero give causes arguments) + self.v.display('EMPTY SLOT') + elif (exitcode == 1): # RV_BADITEM (Dead slot) + self.v.display('EMPTY SLOT') 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) - -""" -Find the price of an item. -""" -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) - -""" -Triggered when the user presses a button while entering their pin. -""" -def handle_getting_pin_key(state, event, params, v, vstatus): - #print "handle_getting_pin_key (s,e,p)", state, " ", event, " ", params - key = params - if len(vstatus.cur_pin) < PIN_LENGTH: - if key == 11: - if vstatus.cur_pin == '': - vstatus.cur_user = '' - reset_idler(v, vstatus) + syslog.syslog(syslog.LOG_INFO | syslog.LOG_LOCAL4, "failed vending %s (slot %s) for %s (code %d)" % (name, self.vstatus.cur_selection, self.vstatus.username, exitcode)) + self.v.display('UNK ERROR') + sleep(1) + """ + Find the price of an item. + """ + def price_check(): + if self.vstatus.cur_selection[1] == '8': + args = ('dispense', 'iteminfo', 'coke:' + self.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( self.vstatus.cur_selection ) + except: + price, shortname, name = get_snack( '--' ) + dollarprice = "$%.2f" % ( price / 100.0 ) + self.v.display(self.vstatus.cur_selection+' - %s'%dollarprice) + + """ + Triggered when the user presses a button while entering their pin. + """ + def handle_getting_pin_key(self, event, params): + key = params + if len(self.vstatus.cur_pin) < PIN_LENGTH: + if key == 11: + if self.vstatus.cur_pin == '': + self.vstatus.cur_user = '' + slef.reset_idler() + + return + self.vstatus.cur_pin = '' + self.vstatus.mk.set_message('PIN: ') return - vstatus.cur_pin = '' - vstatus.mk.set_message('PIN: ') + self.vstatus.cur_pin += chr(key + ord('0')) + self.vstatus.mk.set_message('PIN: '+'X'*len(self.vstatus.cur_pin)) + if len(self.vstatus.cur_pin) == PIN_LENGTH: + self.vstatus.username = self.verify_user_pin(int(self.vstatus.cur_user), int(self.vstatus.cur_pin)) + if self.vstatus.username: + self.v.beep(0, False) + self.vstatus.cur_selection = '' + self.vstatus.change_state(STATE_GET_SELECTION) + self.scroll_options(self.vstatus.username, self.vstatus.mk, True) + return + else: + self.v.beep(40, False) + self.vstatus.mk.set_messages( + [(self.center('BAD PIN'), False, 1.0), + (self.center('SORRY'), False, 0.5)]) + self.vstatus.cur_user = '' + self.vstatus.cur_pin = '' + + self.reset_idler(2) + + return + + """ + Triggered when the user presses a button while entering their user id. + """ + def handle_getting_uid_key(self, event, params): + key = params + # complicated key handling here: + + if len(self.vstatus.cur_user) == 0 and key == 9: + self.vstatus.cur_selection = '' + self.vstatus.time_to_autologout = None + self.vstatus.mk.set_message('PRICECHECK') + sleep(0.5) + self.scroll_options('', vstatus.mk) + self.vstatus.change_state(STATE_GET_SELECTION) return - vstatus.cur_pin += chr(key + ord('0')) - vstatus.mk.set_message('PIN: '+'X'*len(vstatus.cur_pin)) - if len(vstatus.cur_pin) == PIN_LENGTH: - vstatus.username = verify_user_pin(int(vstatus.cur_user), int(vstatus.cur_pin)) - if vstatus.username: - v.beep(0, False) - vstatus.cur_selection = '' - vstatus.change_state(STATE_GET_SELECTION) - scroll_options(vstatus.username, vstatus.mk, True) + + if len(self.vstatus.cur_user) <8: + if key == 11: + self.vstatus.cur_user = '' + + self.reset_idler() return + self.vstatus.cur_user += chr(key + ord('0')) + #logging.info('dob: '+vstatus.cur_user) + if len(self.vstatus.cur_user) > 5: + self.vstatus.mk.set_message('>'+self.vstatus.cur_user) else: - v.beep(40, False) - vstatus.mk.set_messages( - [(center('BAD PIN'), False, 1.0), - (center('SORRY'), False, 0.5)]) - vstatus.cur_user = '' - vstatus.cur_pin = '' - - reset_idler(v, vstatus, 2) + self.vstatus.mk.set_message('UID: '+self.vstatus.cur_user) + + if len(self.vstatus.cur_user) == 5: + uid = int(self.vstatus.cur_user) - return + if uid == 0: + logging.info('user '+self.vstatus.cur_user+' has a bad PIN') + pfalken=""" + CARRIER DETECTED -""" -Triggered when the user presses a button while entering their user id. -""" -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) == 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 = '' + CONNECT 128000 - reset_idler(v, vstatus) - return - vstatus.cur_user += chr(key + ord('0')) - #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) + Welcome to Picklevision Sytems, Sunnyvale, CA - if uid == 0: - logging.info('user '+vstatus.cur_user+' has a bad PIN') - pfalken=""" -CARRIER DETECTED + Greetings Professor Falken. -CONNECT 128000 -Welcome to Picklevision Sytems, Sunnyvale, CA -Greetings Professor Falken. + Shall we play a game? + Please choose from the following menu: -Shall we play a game? + 1. Tic-Tac-Toe + 2. Chess + 3. Checkers + 4. Backgammon + 5. Poker + 6. Toxic and Biochemical Warfare + 7. Global Thermonuclear War + 7 [ENTER] -Please choose from the following menu: + Wouldn't you prefer a nice game of chess? -1. Tic-Tac-Toe -2. Chess -3. Checkers -4. Backgammon -5. Poker -6. Toxic and Biochemical Warfare -7. Global Thermonuclear War + """.replace('\n',' ') + self.vstatus.mk.set_messages([(pfalken, False, 10)]) + self.vstatus.cur_user = '' + self.vstatus.cur_pin = '' + + self.reset_idler(10) -7 [ENTER] + return -Wouldn't you prefer a nice game of chess? + if not self.has_good_pin(uid): + logging.info('user '+self.vstatus.cur_user+' has a bad PIN') + self.vstatus.mk.set_messages( + [(' '*10+'INVALID PIN SETUP'+' '*11, False, 3)]) + self.vstatus.cur_user = '' + self.vstatus.cur_pin = '' + + self.reset_idler(3) -""".replace('\n',' ') - vstatus.mk.set_messages([(pfalken, False, 10)]) - vstatus.cur_user = '' - vstatus.cur_pin = '' + return - reset_idler(v, vstatus, 10) + if self.acct_is_disabled(): + logging.info('user '+self.vstatus.cur_user+' is disabled') + self.vstatus.mk.set_messages( + [(' '*11+'ACCOUNT DISABLED'+' '*11, False, 3)]) + self.vstatus.cur_user = '' + self.vstatus.cur_pin = '' + + self.reset_idler(3) + return - 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'+' '*11, False, 3)]) - vstatus.cur_user = '' - vstatus.cur_pin = '' - - reset_idler(v, vstatus, 3) + self.vstatus.cur_pin = '' + self.vstatus.mk.set_message('PIN: ') + logging.info('need pin for user %s'%self.vstatus.cur_user) + self.vstatus.change_state(STATE_GETTING_PIN) + return + """ + Triggered when a key is pressed and the machine is idling. + """ + def handle_idle_key(self, event, params): + key = params + if key == 11: + self.vstatus.cur_user = '' + self.reset_idler() 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 = '' - vstatus.mk.set_message('PIN: ') - logging.info('need pin for user %s'%vstatus.cur_user) - vstatus.change_state(STATE_GETTING_PIN) - return - -""" -Triggered when a key is pressed and the machine is idling. -""" -def handle_idle_key(state, event, params, v, vstatus): - #print "handle_idle_key (s,e,p)", state, " ", event, " ", params - - key = params - - if key == 11: - vstatus.cur_user = '' - reset_idler(v, vstatus) - return - - vstatus.change_state(STATE_GETTING_UID) - run_handler(event, key, v, vstatus) - -""" -What to do when there is nothing to do. -""" -def handle_idle_tick(state, event, params, v, vstatus): - ### State idling - 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 - choose_idler() - - ### - - vstatus.mk.update_display() - - vstatus.change_state(STATE_GRANDFATHER_CLOCK) - run_handler(event, params, v, vstatus) - sleep(0.05) - -""" -Manages the beeps for the grandfather clock -""" -def beep_on(when, before=0): - start = int(when - before) - end = int(when) - now = int(time()) - - if now >= start and now <= end: - return 1 - return 0 - -def handle_idle_grandfather_tick(state, event, params, v, vstatus): - ### check for interesting times - now = localtime() - - quarterhour = mktime([now[0],now[1],now[2],now[3],15,0,now[6],now[7],now[8]]) - halfhour = mktime([now[0],now[1],now[2],now[3],30,0,now[6],now[7],now[8]]) - threequarterhour = mktime([now[0],now[1],now[2],now[3],45,0,now[6],now[7],now[8]]) - fivetothehour = mktime([now[0],now[1],now[2],now[3],55,0,now[6],now[7],now[8]]) - - hourfromnow = localtime(time() + 3600) - - #onthehour = mktime([now[0],now[1],now[2],now[3],03,0,now[6],now[7],now[8]]) - onthehour = mktime([hourfromnow[0],hourfromnow[1],hourfromnow[2],hourfromnow[3], \ - 0,0,hourfromnow[6],hourfromnow[7],hourfromnow[8]]) - - ## check for X seconds to the hour - ## if case, update counter to 2 - if beep_on(onthehour,15) \ - or beep_on(halfhour,0) \ - or beep_on(quarterhour,0) \ - or beep_on(threequarterhour,0) \ - or beep_on(fivetothehour,0): - vstatus.change_state(STATE_GRANDFATHER_CLOCK,2) - run_handler(event, params, v, vstatus) - else: - vstatus.change_state(STATE_IDLE) + self.vstatus.change_state(STATE_GETTING_UID) + self.run_handler(event, params) + + """ + What to do when there is nothing to do. + """ + def handle_idle_tick(self, event, params): + ### State idling + if self.vstatus.mk.done(): + self.idle_step() + + if self.vstatus.time_of_next_idler and time() > self.vstatus.time_of_next_idler: + self.vstatus.time_of_next_idler = time() + 30 + self.choose_idler() + + ### -def handle_grandfather_tick(state, event, params, v, vstatus): - go_idle = 1 + self.vstatus.mk.update_display() - msg = [] - ### we live in interesting times - now = localtime() + self.vstatus.change_state(STATE_GRANDFATHER_CLOCK) + self.run_handler(event, params) + sleep(0.05) - quarterhour = mktime([now[0],now[1],now[2],now[3],15,0,now[6],now[7],now[8]]) - halfhour = mktime([now[0],now[1],now[2],now[3],30,0,now[6],now[7],now[8]]) - threequarterhour = mktime([now[0],now[1],now[2],now[3],45,0,now[6],now[7],now[8]]) - fivetothehour = mktime([now[0],now[1],now[2],now[3],55,0,now[6],now[7],now[8]]) + """ + Manages the beeps for the grandfather clock + """ + def beep_on(self, when, before=0): + start = int(when - before) + end = int(when) + now = int(time()) - hourfromnow = localtime(time() + 3600) - -# onthehour = mktime([now[0],now[1],now[2],now[3],03,0,now[6],now[7],now[8]]) - onthehour = mktime([hourfromnow[0],hourfromnow[1],hourfromnow[2],hourfromnow[3], \ - 0,0,hourfromnow[6],hourfromnow[7],hourfromnow[8]]) + if now >= start and now <= end: + return 1 + return 0 + def handle_idle_grandfather_tick(self, event, params): + ### check for interesting times + now = localtime() - #print "when it fashionable to wear a onion on your hip" + quarterhour = mktime([now[0],now[1],now[2],now[3],15,0,now[6],now[7],now[8]]) + halfhour = mktime([now[0],now[1],now[2],now[3],30,0,now[6],now[7],now[8]]) + threequarterhour = mktime([now[0],now[1],now[2],now[3],45,0,now[6],now[7],now[8]]) + fivetothehour = mktime([now[0],now[1],now[2],now[3],55,0,now[6],now[7],now[8]]) - if beep_on(onthehour,15): - go_idle = 0 - next_hour=((hourfromnow[3] + 11) % 12) + 1 - if onthehour - time() < next_hour and onthehour - time() > 0: - v.beep(0, False) + hourfromnow = localtime(time() + 3600) + + #onthehour = mktime([now[0],now[1],now[2],now[3],03,0,now[6],now[7],now[8]]) + onthehour = mktime([hourfromnow[0],hourfromnow[1],hourfromnow[2],hourfromnow[3], \ + 0,0,hourfromnow[6],hourfromnow[7],hourfromnow[8]]) + + ## check for X seconds to the hour + ## if case, update counter to 2 + if self.beep_on(onthehour,15) \ + or self.beep_on(halfhour,0) \ + or self.beep_on(quarterhour,0) \ + or self.beep_on(threequarterhour,0) \ + or self.beep_on(fivetothehour,0): + self.vstatus.change_state(STATE_GRANDFATHER_CLOCK,2) + self.run_handler(event, params) + else: + self.vstatus.change_state(STATE_IDLE) - t = int(time()) - if (t % 2) == 0: - msg.append(("DING!", False, None)) - else: - msg.append((" DING!", False, None)) - elif int(onthehour - time()) == 0: - v.beep(255, False) - msg.append((" BONG!", False, None)) - msg.append((" IT'S "+ str(next_hour) + "O'CLOCK AND ALL IS WELL .....", False, TEXT_SPEED*4)) - elif beep_on(halfhour,0): - go_idle = 0 - v.beep(0, False) - msg.append((" HALFHOUR ", False, 50)) - elif beep_on(quarterhour,0): - go_idle = 0 - v.beep(0, False) - msg.append((" QTR HOUR ", False, 50)) - elif beep_on(threequarterhour,0): - go_idle = 0 - v.beep(0, False) - msg.append((" 3 QTR HR ", False, 50)) - elif beep_on(fivetothehour,0): - go_idle = 0 - v.beep(0, False) - msg.append(("Quick run to your lectures! Hurry! Hurry!", False, TEXT_SPEED*4)) - else: + def handle_grandfather_tick(self, event, params): go_idle = 1 - - ## check for X seconds to the hour - - if len(msg): - vstatus.mk.set_messages(msg) - sleep(1) - - vstatus.mk.update_display() - ## if no longer case, return to idle - ## change idler to be clock - if go_idle and vstatus.mk.done(): - vstatus.change_state(STATE_IDLE,1) - -""" -What to do when the door is open. -""" -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. - now = int(time()) - - if ((now % 60 % 2) == 0): - twiddle(now, v) - else: - twiddle(now, v, wise=0) + msg = [] + ### we live in interesting times + now = localtime() -""" -What to do when the door is opened or closed. -""" -def handle_door_event(state, event, params, v, vstatus): - 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 == 1: #door closed - vstatus.change_state(STATE_DOOR_CLOSING) - reset_idler(v, vstatus, 3) - - logging.warning('Leaving open door mode') - v.display("-YUM YUM!-") + quarterhour = mktime([now[0],now[1],now[2],now[3],15,0,now[6],now[7],now[8]]) + halfhour = mktime([now[0],now[1],now[2],now[3],30,0,now[6],now[7],now[8]]) + threequarterhour = mktime([now[0],now[1],now[2],now[3],45,0,now[6],now[7],now[8]]) + fivetothehour = mktime([now[0],now[1],now[2],now[3],55,0,now[6],now[7],now[8]]) -""" -Triggered when a user swipes their caed, and the machine is logged out. -""" -def handle_mifare_event(state, event, params, v, vstatus): - global _last_card_id - card_id = params - # Translate card_id into uid. - if card_id == None or card_id == _last_card_id: - return - - _last_card_id = card_id - - 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 = '' - _last_card_id = -1 - - reset_idler(v, vstatus, 2) - return + hourfromnow = localtime(time() + 3600) + + # onthehour = mktime([now[0],now[1],now[2],now[3],03,0,now[6],now[7],now[8]]) + onthehour = mktime([hourfromnow[0],hourfromnow[1],hourfromnow[2],hourfromnow[3], \ + 0,0,hourfromnow[6],hourfromnow[7],hourfromnow[8]]) -""" -Triggered when a user swipes their card and the machine is logged in. -""" -def handle_mifare_add_user_event(state, event, params, v, vstatus): - global _last_card_id - card_id = params - # Translate card_id into uid. - if card_id == None or card_id == _last_card_id: - return + #print "when it fashionable to wear a onion on your hip" - _last_card_id = card_id - - try: - if get_uid(card_id) != None: - vstatus.mk.set_messages( - [(center('ALREADY'), False, 0.5), - (center('ENROLLED'), False, 0.5)]) + if self.beep_on(onthehour,15): + go_idle = 0 + next_hour=((hourfromnow[3] + 11) % 12) + 1 + if onthehour - time() < next_hour and onthehour - time() > 0: + self.v.beep(0, False) - # scroll_options(vstatus.username, vstatus.mk) + t = int(time()) + if (t % 2) == 0: + msg.append(("DING!", False, None)) + else: + msg.append((" DING!", False, None)) + elif int(onthehour - time()) == 0: + self.v.beep(255, False) + msg.append((" BONG!", False, None)) + msg.append((" IT'S "+ str(next_hour) + "O'CLOCK AND ALL IS WELL .....", False, TEXT_SPEED*4)) + elif self.beep_on(halfhour,0): + go_idle = 0 + self.v.beep(0, False) + msg.append((" HALFHOUR ", False, 50)) + elif self.beep_on(quarterhour,0): + go_idle = 0 + self.v.beep(0, False) + msg.append((" QTR HOUR ", False, 50)) + elif self.beep_on(threequarterhour,0): + go_idle = 0 + self.v.beep(0, False) + msg.append((" 3 QTR HR ", False, 50)) + elif self.beep_on(fivetothehour,0): + go_idle = 0 + self.v.beep(0, False) + msg.append(("Quick run to your lectures! Hurry! Hurry!", False, TEXT_SPEED*4)) + else: + go_idle = 1 + + ## check for X seconds to the hour + + if len(msg): + self.vstatus.mk.set_messages(msg) + sleep(1) + + self.vstatus.mk.update_display() + ## if no longer case, return to idle + + ## change idler to be clock + if go_idle and self.vstatus.mk.done(): + self.vstatus.change_state(STATE_IDLE,1) + + """ + What to do when the door is open. + """ + def handle_door_idle(self, event, params): + 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. + now = int(time()) + + if ((now % 60 % 2) == 0): + twiddle(now, self.v) + else: + twiddle(now, self.v, wise=0) + + """ + What to do when the door is opened or closed. + """ + def handle_door_event(self, event, params): + if params == 0: #door open + self.vstatus.change_state(STATE_DOOR_OPENING) + logging.warning("Entering open door mode") + self.v.display("-FEED ME-") + #door_open_mode(v); + self.vstatus.cur_user = '' + self.vstatus.cur_pin = '' + elif params == 1: #door closed + self.vstatus.change_state(STATE_DOOR_CLOSING) + self.reset_idler(3) + + logging.warning('Leaving open door mode') + self.v.display("-YUM YUM!-") + + """ + Triggered when a user swipes their caed, and the machine is logged out. + """ + def handle_mifare_event(self, event, params): + card_id = params + # Translate card_id into uid. + if card_id == None or card_id == self._last_card_id: 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) - -""" -Maps what to do when the state changes. -""" -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)] = handle_door_event - 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)] = handle_door_event - 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)] = handle_door_event - 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 - vstatus.state_table[(STATE_GRANDFATHER_CLOCK,DOOR,1)] = handle_door_event - vstatus.state_table[(STATE_GRANDFATHER_CLOCK,DOOR,2)] = handle_door_event - 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 - -""" -Get what to do on a state change. -""" -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, USE_MIFARE) - vstatus = VendState(v) - create_state_table(vstatus) - - logging.debug('PING is ' + str(v.ping())) - - if USE_DB: db = DispenseDatabase(v, cf.DBServer, cf.DBName, cf.DBUser, cf.DBPassword) - - setup_idlers(v) - reset_idler(v, vstatus) + self._last_card_id = card_id + + try: + self.vstatus.cur_user = get_uid(card_id) + logging.info('Mapped card id to uid %s'%vstatus.cur_user) + self.vstatus.username = get_uname(vstatus.cur_user) + if self.acct_is_disabled(self.vstatus.username): + self.vstatus.username = '-disabled-' + except ValueError: + self.vstatus.username = None + if self.vstatus.username == '-disabled-': + self.v.beep(40, False) + self.vstatus.mk.set_messages( + [(self.center('ACCT DISABLED'), False, 1.0), + (self.center('SORRY'), False, 0.5)]) + self.vstatus.cur_user = '' + self.vstatus.cur_pin = '' + self.vstatus.username = None + + self.reset_idler(2) + return + elif self.vstatus.username: + self.v.beep(0, False) + self.vstatus.cur_selection = '' + self.vstatus.change_state(STATE_GET_SELECTION) + self.scroll_options(self.vstatus.username, self.vstatus.mk, True) + return + else: + self.v.beep(40, False) + self.vstatus.mk.set_messages( + [(self.center('BAD CARD'), False, 1.0), + (self.center('SORRY'), False, 0.5)]) + self.vstatus.cur_user = '' + self.vstatus.cur_pin = '' + self._last_card_id = -1 + + self.reset_idler(2) + return - while True: - if USE_DB: - try: - db.handle_events() - except DispenseDatabaseException, e: - logging.error('Database error: '+str(e)) + """ + Triggered when a user swipes their card and the machine is logged in. + """ + def handle_mifare_add_user_event(self, evnt, params): + card_id = params - timeout = time_to_next_update(vstatus) - e = v.next_event(timeout) - (event, params) = e + # Translate card_id into uid. + if card_id == None or card_id == self._last_card_id: + return - run_handler(event, params, v, vstatus) + self._last_card_id = card_id + + try: + if get_uid(card_id) != None: + self.vstatus.mk.set_messages( + [(self.center('ALREADY'), False, 0.5), + (self.center('ENROLLED'), False, 0.5)]) -def run_handler(event, params, v, vstatus): - handler = get_state_table_handler(vstatus,vstatus.state,event,vstatus.counter) - if handler: - handler(vstatus.state, event, params, v, vstatus) + # 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)) + self.set_card_id(self.vstatus.cur_user, card_id) + self.vstatus.mk.set_messages( + [(self.center('CARD'), False, 0.5), + (self.center('ENROLLED'), False, 0.5)]) + + # scroll_options(vstatus.username, vstatus.mk) + + def return_to_idle(self, event, params): + self.reset_idler() + + """ + Maps what to do when the state changes. + """ + def create_state_table(self): + self.vstatus.state_table[(STATE_IDLE,TICK,1)] = self.handle_idle_tick + self.vstatus.state_table[(STATE_IDLE,KEY,1)] = self.handle_idle_key + self.vstatus.state_table[(STATE_IDLE,DOOR,1)] = self.handle_door_event + self.vstatus.state_table[(STATE_IDLE,MIFARE,1)] = self.handle_mifare_event + + self.vstatus.state_table[(STATE_DOOR_OPENING,TICK,1)] = self.handle_door_idle + self.vstatus.state_table[(STATE_DOOR_OPENING,DOOR,1)] = self.handle_door_event + self.vstatus.state_table[(STATE_DOOR_OPENING,KEY,1)] = self.do_nothing + self.vstatus.state_table[(STATE_DOOR_OPENING,MIFARE,1)] = self.do_nothing + + self.vstatus.state_table[(STATE_DOOR_CLOSING,TICK,1)] = self.return_to_idle + self.vstatus.state_table[(STATE_DOOR_CLOSING,DOOR,1)] = self.handle_door_event + self.vstatus.state_table[(STATE_DOOR_CLOSING,KEY,1)] = self.do_nothing + self.vstatus.state_table[(STATE_DOOR_CLOSING,MIFARE,1)] = self.do_nothing + + self.vstatus.state_table[(STATE_GETTING_UID,TICK,1)] = self.handle_getting_uid_idle + self.vstatus.state_table[(STATE_GETTING_UID,DOOR,1)] = self.handle_door_event + self.vstatus.state_table[(STATE_GETTING_UID,KEY,1)] = self.handle_getting_uid_key + self.vstatus.state_table[(STATE_GETTING_UID,MIFARE,1)] = self.handle_mifare_event + + self.vstatus.state_table[(STATE_GETTING_PIN,TICK,1)] = self.handle_getting_pin_idle + self.vstatus.state_table[(STATE_GETTING_PIN,DOOR,1)] = self.handle_door_event + self.vstatus.state_table[(STATE_GETTING_PIN,KEY,1)] = self.handle_getting_pin_key + self.vstatus.state_table[(STATE_GETTING_PIN,MIFARE,1)] = self.handle_mifare_event + + self.vstatus.state_table[(STATE_GET_SELECTION,TICK,1)] = self.handle_get_selection_idle + self.vstatus.state_table[(STATE_GET_SELECTION,DOOR,1)] = self.handle_door_event + self.vstatus.state_table[(STATE_GET_SELECTION,KEY,1)] = self.handle_get_selection_key + self.vstatus.state_table[(STATE_GET_SELECTION,MIFARE,1)] = self.handle_mifare_add_user_event + + self.vstatus.state_table[(STATE_GRANDFATHER_CLOCK,TICK,1)] = self.handle_idle_grandfather_tick + self.vstatus.state_table[(STATE_GRANDFATHER_CLOCK,TICK,2)] = self.handle_grandfather_tick + self.vstatus.state_table[(STATE_GRANDFATHER_CLOCK,DOOR,1)] = self.handle_door_event + self.vstatus.state_table[(STATE_GRANDFATHER_CLOCK,DOOR,2)] = self.handle_door_event + self.vstatus.state_table[(STATE_GRANDFATHER_CLOCK,KEY,1)] = self.do_nothing + self.vstatus.state_table[(STATE_GRANDFATHER_CLOCK,KEY,2)] = self.do_nothing + self.vstatus.state_table[(STATE_GRANDFATHER_CLOCK,MIFARE,1)] = self.handle_mifare_event + + """ + Get what to do on a state change. + """ + def get_state_table_handler(self, state, event, counter): + return self.vstatus.state_table[(state,event,counter)] + + def time_to_next_update(self): + idle_update = self.vstatus.time_of_next_idlestep - time() + if not self.vstatus.mk.done() and self.vstatus.mk.next_update is not None: + mk_update = self.vstatus.mk.next_update - time() + if mk_update < idle_update: + idle_update = mk_update + return idle_update + + def run_forever(self, rfh, wfh, options, cf): + self.v = VendingMachine(rfh, wfh, USE_MIFARE) + self.vstatus = VendState(self.v) + self.create_state_table() + + logging.debug('PING is ' + str(self.v.ping())) + + if USE_DB: db = DispenseDatabase(v, cf.DBServer, cf.DBName, cf.DBUser, cf.DBPassword) + + self.setup_idlers() + self.reset_idler() + + while True: + if USE_DB: + try: + db.handle_events() + except DispenseDatabaseException, e: + logging.error('Database error: '+str(e)) + + timeout = self.time_to_next_update() + (event, params) = self.v.next_event(timeout) + self.run_handler(event, params) + + def run_handler(self, event, params): + handler = self.get_state_table_handler(self.vstatus.state,event,self.vstatus.counter) + if handler: + handler(event, params) """ Connect to the machine. @@ -1099,11 +1085,11 @@ def connect_to_vend(options, cf): logging.info('Connecting to vending machine using LAT') latclient = LATClient(service = cf.ServiceName, password = cf.ServicePassword, server_name = cf.ServerName, connect_password = cf.ConnectPassword, priv_password = cf.PrivPassword) rfh, wfh = latclient.get_fh() - elif options.use_serial: - # Open vending machine via serial. - logging.info('Connecting to vending machine using serial') - serialclient = SerialClient(port = '/dev/ttyS1', baud = 9600) - rfh,wfh = serialclient.get_fh() + #elif options.use_serial: + # # Open vending machine via serial. + # logging.info('Connecting to vending machine using serial') + # serialclient = SerialClient(port = '/dev/ttyS1', baud = 9600) + # rfh,wfh = serialclient.get_fh() else: #(rfh, wfh) = popen2('../../virtualvend/vvend.py') logging.info('Connecting to virtual vending machine on %s:%d'%(options.host,options.port)) @@ -1124,8 +1110,8 @@ def parse_args(): from optparse import OptionParser op = OptionParser(usage="%prog [OPTION]...") - 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('-f', '--config-file', default='./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=False, 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') op.add_option('-n', '--hostname', dest='host', default='localhost', help='the hostname to connect to for virtual vending machine mode (default: localhost)') @@ -1230,7 +1216,8 @@ def do_vend_server(options, config_opts): # run_forever(rfh, wfh, options, config_opts) try: - run_forever(rfh, wfh, options, config_opts) + vserver = VendServer() + vserver.run_forever(rfh, wfh, options, config_opts) except VendingException: logging.error("Connection died, trying again...") logging.info("Trying again in 5 seconds.") -- 2.20.1 From 408301a90eee6116aefdd39ead7d9365a22f4a2d Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Sat, 14 Mar 2015 15:18:48 +0800 Subject: [PATCH 10/16] Last few changes, confirmed working on vending machine --- VendServer/VendServer.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/VendServer/VendServer.py b/VendServer/VendServer.py index d6a07a0..6a7af6b 100755 --- a/VendServer/VendServer.py +++ b/VendServer/VendServer.py @@ -642,7 +642,7 @@ class VendServer(): self.vstatus.time_to_autologout = None self.vstatus.mk.set_message('PRICECHECK') sleep(0.5) - self.scroll_options('', vstatus.mk) + self.scroll_options('', self.vstatus.mk) self.vstatus.change_state(STATE_GET_SELECTION) return @@ -923,8 +923,8 @@ class VendServer(): try: self.vstatus.cur_user = get_uid(card_id) - logging.info('Mapped card id to uid %s'%vstatus.cur_user) - self.vstatus.username = get_uname(vstatus.cur_user) + logging.info('Mapped card id to uid %s'%self.vstatus.cur_user) + self.vstatus.username = get_uname(self.vstatus.cur_user) if self.acct_is_disabled(self.vstatus.username): self.vstatus.username = '-disabled-' except ValueError: @@ -981,8 +981,8 @@ class VendServer(): except ValueError: pass - logging.info('Enrolling card %s to uid %s (%s)'%(card_id, vstatus.cur_user, vstatus.username)) - self.set_card_id(self.vstatus.cur_user, card_id) + logging.info('Enrolling card %s to uid %s (%s)'%(card_id, self.vstatus.cur_user, self.vstatus.username)) + self.set_card_id(self.vstatus.cur_user, self.card_id) self.vstatus.mk.set_messages( [(self.center('CARD'), False, 0.5), (self.center('ENROLLED'), False, 0.5)]) @@ -1085,11 +1085,11 @@ def connect_to_vend(options, cf): logging.info('Connecting to vending machine using LAT') latclient = LATClient(service = cf.ServiceName, password = cf.ServicePassword, server_name = cf.ServerName, connect_password = cf.ConnectPassword, priv_password = cf.PrivPassword) rfh, wfh = latclient.get_fh() - #elif options.use_serial: - # # Open vending machine via serial. - # logging.info('Connecting to vending machine using serial') - # serialclient = SerialClient(port = '/dev/ttyS1', baud = 9600) - # rfh,wfh = serialclient.get_fh() + elif options.use_serial: + # Open vending machine via serial. + logging.info('Connecting to vending machine using serial') + serialclient = SerialClient(port = '/dev/ttyS1', baud = 9600) + rfh,wfh = serialclient.get_fh() else: #(rfh, wfh) = popen2('../../virtualvend/vvend.py') logging.info('Connecting to virtual vending machine on %s:%d'%(options.host,options.port)) @@ -1110,7 +1110,7 @@ def parse_args(): from optparse import OptionParser op = OptionParser(usage="%prog [OPTION]...") - op.add_option('-f', '--config-file', default='./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=False, 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') -- 2.20.1 From a0c785ac1d572b82cb214a61e62d8443b3927e7c Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Thu, 2 Apr 2015 21:55:16 +0800 Subject: [PATCH 11/16] Fix up dispense abstraction --- VendServer/DispenseInterface.py | 39 ++++--- VendServer/OpenDispense.py | 176 ++++++++++++++++++-------------- 2 files changed, 127 insertions(+), 88 deletions(-) diff --git a/VendServer/DispenseInterface.py b/VendServer/DispenseInterface.py index 7af3653..94b2367 100644 --- a/VendServer/DispenseInterface.py +++ b/VendServer/DispenseInterface.py @@ -10,67 +10,82 @@ class DispenseInterface(object): """ Create a new dispense object. + @param username The username to connect to dispense with + @param secret The secret to use for Auth """ - def __init__(self, username=None, loggedIn=False, disabled=False): + def __init__(self, username=None, secret=None): pass """ Create a new dispense interface as the supplied user. + @param username The userid of the person authing to dispense + @param pin Thier pin """ - @staticmethod - def authUsernamePin(username, pin): + def authUsernamePin(self, userId, pin): pass """ Create a new dispense interface as the supplied user. + @param cardId The card that someone is connecting to Dispense with """ - @staticmethod - def authMifare(cardId): + def authMifare(self, cardId): pass """ Add a MIFARE card for this user + @param cardId Card to add to a user account + @return 1 if added successfully, anything else otherwise """ def addCard(self, cardId): pass """ Check if creating the user worked correctly. + @return True if currently logged in as a user, false otherwise """ def isLoggedIn(self): pass """ - Get the users username. + Get the current users username. + @return The username of the current user. An empty string if not currently logged in. """ - def getUsername(self, user): + def getUsername(self): pass """ - Get the users current balance. + Get the current users balance. + @return the users balance. None if not logged in. """ - def getBalance(self, user): + def getBalance(self): pass """ Get the name and price of an item. - itemId is the number entered into the vending machine + @param itemId The number entered into the vending machine + @return (itemname, price) """ - @staticmethod def getItemInfo(itemId): pass """ Check if the user is disabled. + @return True if the user is disabled """ def isDisabled(self): pass """ Dispense an item for the current user. - itemId is the number entered into the vending machine + @param itemId The number entered into the vending machine """ def dispenseItem(self, itemId): pass + """ + Log the current user out + """ + def logOut(self): + pass + diff --git a/VendServer/OpenDispense.py b/VendServer/OpenDispense.py index f8cee0d..b4f481c 100644 --- a/VendServer/OpenDispense.py +++ b/VendServer/OpenDispense.py @@ -1,10 +1,3 @@ -from DispenseInterface import DispenseInterface -import os -import re -import pwd -from subprocess import Popen, PIPE -from LDAPConnector import get_uid,get_uname, set_card_id - """ Author: Mitchell Pomery (bobgeorge33) @@ -13,97 +6,128 @@ Most of this code has been copied out of VendServer.py, then had variables updat This is so VendServer can easily operate regardless of the current accounting backend. Documentation for this code can be found inder Dispence.DispenceInterface """ + +from DispenseInterface import DispenseInterface +import os +import re +import pwd +from subprocess import Popen, PIPE +from LDAPConnector import get_uid,get_uname, set_card_id + class OpenDispense(DispenseInterface): - _username = None - _disabled = True - _loggedIn = False + _username = "" + _disabled = True + _loggedIn = False _userId = None - def __init__(self, userId=None, username=None, loggedIn=False): - self._username = username - self._loggedIn = loggedIn - self._userId = userId - - acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate() - # this is fucking appalling - flags = acct[acct.find("(")+1:acct.find(")")].strip() - if 'disabled' in flags: - self._disabled = True - if 'internal' in flags: - self._disabled = True - self._disabled = False + def __init__(self, username=None, secret=False): + pass - @staticmethod - def authUserIdPin(userId, pin): + def authUserIdPin(self, userId, pin): try: # Get info from - info = pwd.getpwuid(userId) - 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().strip() - f.close() - if not re.search('^[0-9]{4}$', pinstr): - logging.info('getting pin for uid %d: %s not a good pin'%(uid,repr(pinstr))) - return None - return OpenDispense(userId, info.pw_name, (int(pin)==int(pinstr))) + info = pwd.getpwuid(userId) + except KeyError: + logging.info('getting pin for uid %d: user not in password file'%userId) + return False - @staticmethod - def authMifareCard(cardId): - return OpenDispense(get_uid(cardId), get_uname(get_uid(cardId)), True) + 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'%userId) + return False + if s.st_mode & 077: + logging.info('getting pin for uid %d: .pin has wrong permissions. Fixing.'%userId) + os.chmod(pinfile, 0600) + try: + f = file(pinfile) + except IOError: + logging.info('getting pin for uid %d: I cannot read pin file'%userId) + return False + pinstr = f.readline().strip() + f.close() + if not re.search('^[0-9]{4}$', pinstr): + logging.info('getting pin for uid %d: %s not a good pin'%(userId,repr(pinstr))) + return False + + if pinstr == str(pin): + #Login Successful + self._userid = userId + self._loggedIn = True + self._disabled = False + self._username = info.pw_name + return True + + # Login Unsuccessful + return False + + def authMifareCard(self, cardId): + # Get the users ID + self._userid = get_uid(cardId) + + # Check for thier username + try: + # Get info from + info = pwd.getpwuid(userId) + except KeyError: + logging.info('getting pin for uid %d: user not in password file'%uid) + return False + + # If we get this far all is good + self._loggedIn = True + self._disabled = False + self._username = info.pw_name + return True def addCard(self, cardId): - set_card_id(self._userId, cardId) + if self.isLoggedIn(): + set_card_id(self._userId, cardId) + return True - def isLoggedIn(self): - return self._loggedIn + def isLoggedIn(self): + return self._loggedIn - def getUsername(self): - return self._username + def getUsername(self): + return self._username - def getBalance(self): + def getBalance(self): # Balance checking - acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate() - # this is fucking appalling - balance = acct[acct.find("$")+1:acct.find("(")].strip() - return balance + if self.isLoggedIn(): + acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate() + else: + return None + balance = acct[acct.find("$")+1:acct.find("(")].strip() + return balance - def getItemInfo(itemId): + def getItemInfo(self, itemId): itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId) args = ('dispense', 'iteminfo', itemId) - 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)) + info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate() + m = re.match("\s*[a-z]+:\d+\s+(\d+)\.(\d\d)\s+([^\n]+)", info) + if m == None: + return("dead", 0) + cents = int(m.group(1))*100 + int(m.group(2)) # return (name, price in cents) - return (m.group(3), cents) + return (m.group(3), cents) - def isDisabled(self): - return False + def isDisabled(self): + return self._disabled - def dispenseItem(self, itemId): - itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId) - if itemId == "": + def dispenseItem(self, itemId): + if not self.isLoggedIn() or self.getItemInfo(itemId)[0] == "dead": return False else: print('dispense -u "%s" %s'%(self._username, itemId)) - os.system('dispense -u "%s" %s'%(self._username, itemId)) - return True + #os.system('dispense -u "%s" %s'%(self._username, itemId)) + return True + + def logOut(self): + self._username = "" + self._disabled = True + self._loggedIn = False + self._userId = None """ This class abstracts the idea of item numbers. -- 2.20.1 From 9d34b41fdab2ec8c3cc05a119ab8295dffc80f76 Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Sat, 4 Apr 2015 12:10:58 +0800 Subject: [PATCH 12/16] Implimenting the abstracted dispense class into the code --- VendServer/VendServer.py | 116 ++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 62 deletions(-) diff --git a/VendServer/VendServer.py b/VendServer/VendServer.py index 6a7af6b..f642dc4 100755 --- a/VendServer/VendServer.py +++ b/VendServer/VendServer.py @@ -164,38 +164,33 @@ class VendServer(): _pin_pin = '----' _last_card_id = -1 + dispense = None + """ Show information to the user as to what can be dispensed. """ def scroll_options(self, username, mk, welcome = False): # If the user has just logged in, show them their balance 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() + balance = dispense.getBalance() msg = [(self.center('WELCOME'), False, TEXT_SPEED), - (self.center(username), False, TEXT_SPEED), + (self.center(self.dispense.getUsername()), False, TEXT_SPEED), (self.center(balance), False, TEXT_SPEED),] else: msg = [] choices = ' '*10+'CHOICES: ' # Show what is in the coke machine + # Need to update this so it uses the abstracted system 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 i in ['08', '18', '28', '38', '48', '58', '68']: + cokes.append((i, self.dispense.getItemInfo(i))) for c in cokes: - c = c.strip() - (slot_num, price, slot_name) = c.split(' ', 2) - if slot_name == 'dead': continue - choices += '%s-(%sc)-%s8 '%(slot_name, price, slot_num) + if c[1][0] == 'dead': + continue + choices += '%s-(%sc)-%s8 '%(c[1][0], c[1][1], c[0]) # Show the final few options choices += '55-DOOR ' @@ -210,6 +205,7 @@ class VendServer(): """ Verify the users pin """ + """ def _check_pin(self, uid, pin): print "_check_pin('",uid,"',---)" if uid != self._pin_uid: @@ -219,7 +215,7 @@ class VendServer(): 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') + pinfile = os.path.join(info.pw_dir, '.pin') try: s = os.stat(pinfile) except OSError: @@ -248,10 +244,12 @@ class VendServer(): else: logging.info("Pin incorrect for %d",uid) return pin == int(pinstr) + """ """ Check if the users account has been disabled """ + """ def acct_is_disabled(self, name=None): if name == None: name = self._pin_uname @@ -263,16 +261,20 @@ class VendServer(): if 'internal' in flags: return True return False + """ """ Check that the user has a valid pin set """ + """ def has_good_pin(self, uid): return self._check_pin(uid, None) != None + """ """ Verify the users pin. """ + """ def verify_user_pin(self, uid, pin, skip_pin_check=False): if skip_pin_check or self._check_pin(uid, pin) == True: info = pwd.getpwuid(uid) @@ -287,6 +289,7 @@ class VendServer(): else: logging.info('refused pin for uid %d'%(uid)) return None + """ """ In here just for fun. @@ -511,7 +514,7 @@ class VendServer(): self.vstatus.last_timeout_refresh = None else: # Price check mode. - self.price_check() + self.dispense.getItemInfo(self.vstatus.cur_selection) self.vstatus.cur_selection = '' self.vstatus.time_to_autologout = None self.vstatus.last_timeout_refresh = None @@ -579,6 +582,7 @@ class VendServer(): """ Find the price of an item. """ + """ def price_check(): if self.vstatus.cur_selection[1] == '8': args = ('dispense', 'iteminfo', 'coke:' + self.vstatus.cur_selection[0]) @@ -592,6 +596,7 @@ class VendServer(): price, shortname, name = get_snack( '--' ) dollarprice = "$%.2f" % ( price / 100.0 ) self.v.display(self.vstatus.cur_selection+' - %s'%dollarprice) + """ """ Triggered when the user presses a button while entering their pin. @@ -611,8 +616,8 @@ class VendServer(): self.vstatus.cur_pin += chr(key + ord('0')) self.vstatus.mk.set_message('PIN: '+'X'*len(self.vstatus.cur_pin)) if len(self.vstatus.cur_pin) == PIN_LENGTH: - self.vstatus.username = self.verify_user_pin(int(self.vstatus.cur_user), int(self.vstatus.cur_pin)) - if self.vstatus.username: + self.dispense.authUserIdPin(self.vstatus.cur_user, self.vstatus.cur_pin) + if self.dispense.getUsername(): self.v.beep(0, False) self.vstatus.cur_selection = '' self.vstatus.change_state(STATE_GET_SELECTION) @@ -702,6 +707,7 @@ class VendServer(): return + """ if not self.has_good_pin(uid): logging.info('user '+self.vstatus.cur_user+' has a bad PIN') self.vstatus.mk.set_messages( @@ -712,8 +718,9 @@ class VendServer(): self.reset_idler(3) return - - if self.acct_is_disabled(): + """ + + if self.dispense.isDisabled(): logging.info('user '+self.vstatus.cur_user+' is disabled') self.vstatus.mk.set_messages( [(' '*11+'ACCOUNT DISABLED'+' '*11, False, 3)]) @@ -921,47 +928,37 @@ class VendServer(): self._last_card_id = card_id - try: - self.vstatus.cur_user = get_uid(card_id) - logging.info('Mapped card id to uid %s'%self.vstatus.cur_user) - self.vstatus.username = get_uname(self.vstatus.cur_user) - if self.acct_is_disabled(self.vstatus.username): - self.vstatus.username = '-disabled-' - except ValueError: - self.vstatus.username = None - if self.vstatus.username == '-disabled-': + self.dispense.authMifareCard(card_id) + logging.info('Mapped card id to uid %s'%self.dispense.getUsername()) + if not self.dispense.isLoggedIn(): self.v.beep(40, False) self.vstatus.mk.set_messages( - [(self.center('ACCT DISABLED'), False, 1.0), + [(self.center('BAD CARD'), False, 1.0), (self.center('SORRY'), False, 0.5)]) self.vstatus.cur_user = '' self.vstatus.cur_pin = '' - self.vstatus.username = None + self._last_card_id = -1 self.reset_idler(2) return - elif self.vstatus.username: - self.v.beep(0, False) - self.vstatus.cur_selection = '' - self.vstatus.change_state(STATE_GET_SELECTION) - self.scroll_options(self.vstatus.username, self.vstatus.mk, True) - return - else: + elif self.dispense.isDisabled(): self.v.beep(40, False) self.vstatus.mk.set_messages( - [(self.center('BAD CARD'), False, 1.0), + [(self.center('ACCT DISABLED'), False, 1.0), (self.center('SORRY'), False, 0.5)]) - self.vstatus.cur_user = '' - self.vstatus.cur_pin = '' - self._last_card_id = -1 - + self.dispense.logOut() self.reset_idler(2) return + else: + self.vstatus.cur_selection = '' + self.vstatus.change_state(STATE_GET_SELECTION) + self.scroll_options(self.vstatus.username, self.vstatus.mk, True) + return """ Triggered when a user swipes their card and the machine is logged in. """ - def handle_mifare_add_user_event(self, evnt, params): + def handle_mifare_add_user_event(self, event, params): card_id = params # Translate card_id into uid. @@ -969,25 +966,19 @@ class VendServer(): return self._last_card_id = card_id - - try: - if get_uid(card_id) != None: - self.vstatus.mk.set_messages( - [(self.center('ALREADY'), False, 0.5), - (self.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, self.vstatus.cur_user, self.vstatus.username)) - self.set_card_id(self.vstatus.cur_user, self.card_id) - self.vstatus.mk.set_messages( - [(self.center('CARD'), False, 0.5), - (self.center('ENROLLED'), False, 0.5)]) + res = self.dispense.addCard(card_id) - # scroll_options(vstatus.username, vstatus.mk) + if get_uid(card_id) != None: + self.vstatus.mk.set_messages( + [(self.center('ALREADY'), False, 0.5), + (self.center('ENROLLED'), False, 0.5)]) + else: + logging.info('Enrolling card %s to uid %s (%s)'%(card_id, self.vstatus.cur_user, self.vstatus.username)) + self.set_card_id(self.vstatus.cur_user, self.card_id) + self.vstatus.mk.set_messages( + [(self.center('CARD'), False, 0.5), + (self.center('ENROLLED'), False, 0.5)]) def return_to_idle(self, event, params): self.reset_idler() @@ -1050,6 +1041,7 @@ class VendServer(): def run_forever(self, rfh, wfh, options, cf): self.v = VendingMachine(rfh, wfh, USE_MIFARE) + self.dispense = Dispense() self.vstatus = VendState(self.v) self.create_state_table() -- 2.20.1 From d51a435a9b62496dd3388c6db2280c0bfb3a49eb Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Sat, 4 Apr 2015 12:23:29 +0800 Subject: [PATCH 13/16] Minor bug fixes to get it working --- VendServer/OpenDispense.py | 2 +- VendServer/VendServer.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/VendServer/OpenDispense.py b/VendServer/OpenDispense.py index b4f481c..4eadcf6 100644 --- a/VendServer/OpenDispense.py +++ b/VendServer/OpenDispense.py @@ -26,7 +26,7 @@ class OpenDispense(DispenseInterface): def authUserIdPin(self, userId, pin): try: # Get info from - info = pwd.getpwuid(userId) + info = pwd.getpwuid(int(userId)) except KeyError: logging.info('getting pin for uid %d: user not in password file'%userId) return False diff --git a/VendServer/VendServer.py b/VendServer/VendServer.py index f642dc4..dd35cd4 100755 --- a/VendServer/VendServer.py +++ b/VendServer/VendServer.py @@ -172,7 +172,7 @@ class VendServer(): def scroll_options(self, username, mk, welcome = False): # If the user has just logged in, show them their balance if welcome: - balance = dispense.getBalance() + balance = self.dispense.getBalance() msg = [(self.center('WELCOME'), False, TEXT_SPEED), (self.center(self.dispense.getUsername()), False, TEXT_SPEED), @@ -720,6 +720,7 @@ class VendServer(): return """ + """ if self.dispense.isDisabled(): logging.info('user '+self.vstatus.cur_user+' is disabled') self.vstatus.mk.set_messages( @@ -729,7 +730,7 @@ class VendServer(): self.reset_idler(3) return - + """ self.vstatus.cur_pin = '' self.vstatus.mk.set_message('PIN: ') -- 2.20.1 From db55f34efc5c9d66c9608176c4b66162ee9e7318 Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Sat, 4 Apr 2015 13:59:39 +0800 Subject: [PATCH 14/16] Removed large chunks of unused code --- VendServer/VendServer.py | 123 +-------------------------------------- 1 file changed, 1 insertion(+), 122 deletions(-) diff --git a/VendServer/VendServer.py b/VendServer/VendServer.py index dd35cd4..21fe2c8 100755 --- a/VendServer/VendServer.py +++ b/VendServer/VendServer.py @@ -201,96 +201,6 @@ class VendServer(): # Send it to the display mk.set_messages(msg) - - """ - Verify the users pin - """ - """ - def _check_pin(self, uid, pin): - print "_check_pin('",uid,"',---)" - if uid != self._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 - self._pin_uid = uid - self._pin_pin = pinstr - self._pin_uname = info.pw_name - else: - pinstr = self._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) - """ - - """ - Check if the users account has been disabled - """ - """ - def acct_is_disabled(self, name=None): - if name == None: - name = self._pin_uname - acct, unused = Popen(['dispense', 'acct', self._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 - """ - - """ - Check that the user has a valid pin set - """ - """ - def has_good_pin(self, uid): - return self._check_pin(uid, None) != None - """ - - """ - Verify the users pin. - """ - """ - def verify_user_pin(self, uid, pin, skip_pin_check=False): - if skip_pin_check or self._check_pin(uid, pin) == True: - info = pwd.getpwuid(uid) - if skip_pin_check: - if self.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)) - return None - """ - """ In here just for fun. """ @@ -579,25 +489,6 @@ class VendServer(): self.v.display('UNK ERROR') sleep(1) - """ - Find the price of an item. - """ - """ - def price_check(): - if self.vstatus.cur_selection[1] == '8': - args = ('dispense', 'iteminfo', 'coke:' + self.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( self.vstatus.cur_selection ) - except: - price, shortname, name = get_snack( '--' ) - dollarprice = "$%.2f" % ( price / 100.0 ) - self.v.display(self.vstatus.cur_selection+' - %s'%dollarprice) - """ - """ Triggered when the user presses a button while entering their pin. """ @@ -707,19 +598,7 @@ class VendServer(): return - """ - if not self.has_good_pin(uid): - logging.info('user '+self.vstatus.cur_user+' has a bad PIN') - self.vstatus.mk.set_messages( - [(' '*10+'INVALID PIN SETUP'+' '*11, False, 3)]) - self.vstatus.cur_user = '' - self.vstatus.cur_pin = '' - - self.reset_idler(3) - - return - """ - + # TODO Fix this up do we can check before logging in """ if self.dispense.isDisabled(): logging.info('user '+self.vstatus.cur_user+' is disabled') -- 2.20.1 From 4fa885832355d6e46f959c013cb8e1b729a96786 Mon Sep 17 00:00:00 2001 From: Mark Tearle Date: Mon, 6 Apr 2015 16:44:22 +0800 Subject: [PATCH 15/16] Remove dot twiddling on display --- VendServer/VendingMachine.py | 1 - 1 file changed, 1 deletion(-) diff --git a/VendServer/VendingMachine.py b/VendServer/VendingMachine.py index e5a0251..4f4b674 100644 --- a/VendServer/VendingMachine.py +++ b/VendServer/VendingMachine.py @@ -162,7 +162,6 @@ class VendingMachine: def display(self, string): if len(string) > 10: string = string[0:10] - string = re.sub('(.)\.', lambda match: '.'+match.group(1), string) self.wfh.write('D'+string+'\n') (code, string) = self.get_response() return (code == '300', code, string) -- 2.20.1 From 87f1523daa4745e91c2f199869c80424d30b4c02 Mon Sep 17 00:00:00 2001 From: Mark Tearle Date: Mon, 6 Apr 2015 17:02:08 +0800 Subject: [PATCH 16/16] Alter display code to pad with spaces and simplify --- VendServer/VendingMachine.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/VendServer/VendingMachine.py b/VendServer/VendingMachine.py index 4f4b674..72cec3d 100644 --- a/VendServer/VendingMachine.py +++ b/VendServer/VendingMachine.py @@ -160,9 +160,9 @@ class VendingMachine: return (code == '501', code, string) def display(self, string): - if len(string) > 10: - string = string[0:10] - self.wfh.write('D'+string+'\n') + # display first ten characters of string, left aligned + self.wfh.write('D%-10.10s\n' % string) + (code, string) = self.get_response() return (code == '300', code, string) -- 2.20.1