diff --git a/VendServer/HorizScroll.py b/VendServer/HorizScroll.py index 23811f06e7ea0f6a1c60c227b04377450d17203f..9687c8299e03b64c385fc1651724c644cef71d95 100644 --- a/VendServer/HorizScroll.py +++ b/VendServer/HorizScroll.py @@ -14,10 +14,9 @@ class HorizScroll: return [self.text] if padding == None: - padding = len(self.text) / 2 + 1 + padding = len(self.text) // 2 + 1 - format = "%-" + str(padding) + "." + str(padding) + "s" - pad = string.replace(format % " "," ",paddingchar) + pad = paddingchar * padding padtext = self.text + pad if not wraparound: numiters = len(self.text) - 10 diff --git a/VendServer/Idler.py b/VendServer/Idler.py index 493f209124709cb71e9e91e97e56770269488ed5..d3cab072a6f70c64ab7469b7cd319dd3a88c7456 100755 --- a/VendServer/Idler.py +++ b/VendServer/Idler.py @@ -62,7 +62,7 @@ class TrainIdler(Idler): Idler.__init__(self, v) self.idle_state = 0 - def put_shark(self, s, l): + def put_shark(self, s: str, l: int): if self.s[l] == ' ': self.s[l] = s elif self.s[l] == 'X': @@ -79,13 +79,13 @@ class TrainIdler(Idler): else: self.put_shark('^', 18-shark1) - shark2 = ((self.idle_state+4) % 36)/2 + shark2 = ((self.idle_state+4) % 36)//2 if shark2 < 9: self.put_shark('<', shark2) else: self.put_shark('<', 18-shark2) - shark3 = ((self.idle_state+7) % 54)/3 + shark3 = ((self.idle_state+7) % 54)//3 if shark3 < 9: self.put_shark('>', 9-shark3) else: @@ -112,7 +112,7 @@ class TrainIdler(Idler): ptr = i+train3-train3_start-10 if ptr >= 0 and ptr < 10: self.s[ptr] = '-' - self.v.display(string.join(self.s, '')) + self.v.display(''.join(self.s)) self.idle_state += 1 self.idle_state %= 18*36*54 @@ -139,7 +139,7 @@ class OrderMaker: j = 0 res = [] while i >= 0: - a = index/self.factorial[i] + a = index // self.factorial[i] index %= self.factorial[i] res.append(a+1) i -= 1 @@ -172,16 +172,16 @@ class GrayIdler(Idler): output = self.do_next_state() # does the next stage of a dance if self.zero: - output = string.replace(output, "0", self.zero) + output = output.replace("0", self.zero) if self.one: - output = string.replace(output, "1", self.one) + output = output.replace("1", self.one) if self.reorder: global orderings newoutput = "" for i in range(0,8): newoutput += output[orderings[self.reorder][i]] output = newoutput - self.v.display(" %8.8s " % (output)) + self.v.display(" %8.8s " % (output,)) self.i = (self.i + 1) % self.size def do_next_state(self): @@ -241,14 +241,14 @@ class StringIdler(Idler): msg = [("",False, None),(self.text, repeat, IDLER_TEXT_SPEED)] self.mk.set_messages(msg) - def clean_text(self, text): + def clean_text(self, text: str): # nothing like a bit of good clean text :) valid = string.digits \ - + string.letters \ + + string.ascii_letters \ + string.punctuation \ + " " # uppercase it - text = string.upper(text) + text = text.upper() clean = "" for char in text: if char in valid: @@ -283,7 +283,7 @@ class FortuneIdler(StringIdler): text = "I broke my wookie...." if os.access(fortune,os.F_OK|os.X_OK): (lines, unused) = Popen((fortune,), close_fds=True, stdout=PIPE).communicate() - text = lines.replace('\n', ' ').replace('\r', '') + text = lines.decode('utf-8').replace('\n', ' ').replace('\r', '') StringIdler.__init__(self, v, text,repeat=False, affinity=affinity) def reset(self): @@ -295,7 +295,7 @@ class PipeIdler(StringIdler): text = "I ate my cookie...." if os.access(command,os.F_OK|os.X_OK): (lines, unused) = Popen([command,] + args.split(), close_fds=True, stdout=PIPE).communicate() - text = lines.replace('\n', ' ').replace('\r', '') + text = lines.decode('utf-8').replace('\n', ' ').replace('\r', '') StringIdler.__init__(self, v, text,repeat=False, affinity=affinity) class FileIdler(StringIdler): @@ -304,6 +304,6 @@ class FileIdler(StringIdler): if os.access(thefile,os.F_OK|os.R_OK): f = open(thefile,'r') - text = string.join(f.readlines()) + text = "".join(f.readlines()) f.close() StringIdler.__init__(self, v, text,repeat=False, affinity=affinity) diff --git a/VendServer/MIFAREClient.py b/VendServer/MIFAREClient.py index 96e19434f90264d921bece4d2f9e424ab55d5d01..8adf2336cc699bd8ec369d692e00af7a8da79ea3 100644 --- a/VendServer/MIFAREClient.py +++ b/VendServer/MIFAREClient.py @@ -1,6 +1,5 @@ from .MIFAREDriver import MIFAREReader, MIFAREException from serial import Serial -from .LDAPConnector import get_uid, set_card_id class MIFAREClient: def __init__(self): @@ -20,25 +19,3 @@ class MIFAREClient: self.reader.set_led(red = False, green = True) self.reader.beep(100) return card_id - - def get_card_uid(self): - card_id = self.get_card_id() - if card_id == None: - return None - else: - return get_uid(card_id) - - def add_card(self, uid): - self.reader.set_led(red = True, green = False) - for attempt in range(5): - self.reader.beep(50) - try: - card_id, capacity = self.reader.select_card() - except MIFAREException: - pass - else: - set_card_id(uid, card_id) - self.reader.set_led(red = False, green = True) - return True - self.reader.set_led(red = False, green = True) - return False diff --git a/VendServer/OpenDispense.py b/VendServer/OpenDispense.py index 63f85afa087f9ff49e54839748070f8b74f56021..6ada5be678525c43905f745bb76ee10eadcda1d8 100644 --- a/VendServer/OpenDispense.py +++ b/VendServer/OpenDispense.py @@ -15,10 +15,9 @@ import pwd import base64 import socket from subprocess import Popen, PIPE -from .LDAPConnector import get_uid,get_uname, set_card_id +#from .LDAPConnector import get_uid,get_uname, set_card_id DISPENSE_ENDPOINT = ("localhost", 11020) -DISPSRV_MIFARE = True # A list of cards that should never be registered, and should never log in # - Some of these might have been registered before we knew they were duplicates @@ -36,11 +35,35 @@ class OpenDispense(DispenseInterface): def __init__(self, username=None, secret=False): pass - def authUserIdPin(self, userId, pin): + def authUserIdPin(self, userId: str, pin: str): return self.authUserIdPin_db(userId, pin) #return self.authUserIdPin_file(userId, pin) - def authUserIdPin_db(self, userId, pin): + def _connect(self, authenticte:bool=True, set_euid:bool=False): + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + try: + sock.connect(DISPENSE_ENDPOINT) + except ConnectionRefusedError: + logging.error("Cannot connect to dispsrv on {}".format(DISPENSE_ENDPOINT,)) + return None + logging.debug('connected to dispsrv') + conn = Connection( sock.makefile('rw', encoding='utf-8') ) + if authenticte: + rsp = conn.send_command("AUTHIDENT") + if not "200" in rsp: + logging.info('Server said no to AUTHIDENT! - %r' % (rsp,)) + return None + logging.debug('authenticated') + if set_euid: + rsp = conn.send_command("SETEUSER %s" % (self._username,)) + if not "200" in rsp: + logging.info('Server said no to SETEUSER! - %r' % (rsp,)) + return None + + return conn + + def authUserIdPin_db(self, userId: str, pin: str): userId = int(userId) try: @@ -50,18 +73,13 @@ class OpenDispense(DispenseInterface): logging.info('getting pin for uid %d: user not in password file'%userId) return False - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - sock.connect(DISPENSE_ENDPOINT) - logging.debug('connected to dispsrv') - sockf = sock.makefile() - sockf.write("AUTHIDENT\n"); sockf.flush() - rsp = sockf.readline() - assert "200" in rsp - logging.debug('authenticated') - sockf.write("PIN_CHECK %s %s\n" % (info.pw_name, pin)); sockf.flush() - rsp = sockf.readline() + conn = self._connect(authenticte=True) + if conn is None: + logging.error("getting pin for uid {}: Unable to open connection".format(userId)) + return False + rsp = conn.send_command("PIN_CHECK %s %s" % (info.pw_name, pin,)) if not "200" in rsp: - logging.info('checking pin for uid %d: Server said no - %r' % (userId, rsp)) + logging.info('checking pin for uid %d: Server said no (PIN_CHECK) - %r' % (userId, rsp)) return False #Login Successful logging.info('accepted pin for uid %d \'%s\'' % (userId, info.pw_name)) @@ -71,7 +89,7 @@ class OpenDispense(DispenseInterface): self._username = info.pw_name return True - def authUserIdPin_file(self, userId, pin): + def authUserIdPin_file(self, userId: str, pin: str): userId = int(userId) try: @@ -116,51 +134,34 @@ class OpenDispense(DispenseInterface): def authMifareCard(self, cardId): self._loggedIn = False self._username = None - if DISPSRV_MIFARE: - card_base64 = base64.b64encode(cardId) - - if card_base64 in CARD_BLACKLIST: - logging.info("Blacklisted card base64:%s" % (card_base64,)) - return False - - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - sock.connect(DISPENSE_ENDPOINT) - logging.debug('connected to dispsrv') - sockf = sock.makefile() - sockf.write("AUTHIDENT\n"); sockf.flush() - rsp = sockf.readline() - assert "200" in rsp - logging.debug('authenticated') - sockf.write("AUTHCARD %s\n" % (card_base64,)); sockf.flush() - rsp = sockf.readline() - if not "200" in rsp: - logging.info("Rejected card base64:%s" % (card_base64,)) - return False - username = rsp.split('=')[1].strip() - logging.info("Accepted card base64:%s for %s" % (card_base64,username,)) + + card_base64 = base64.b64encode(cardId) - ## Check for thier username - #try: - # # Get info from the system (by username) - # info = pwd.getpwnam(username) - #except KeyError: - # logging.info('getting info for user \'%s\': user not in password file' % (username,)) - # return False - #self._userid = info.pw_uid - self._userid = None - self._username = username - else: - # Get the users ID - self._userid = get_uid(cardId) + if card_base64 in CARD_BLACKLIST: + logging.info("Blacklisted card base64:%s" % (card_base64,)) + return False + + conn = self._connect() + if conn is None: + logging.error("getting username for card {}: Unable to open connection".format(card_base64)) + return False + rsp = conn.send_command("AUTHCARD %s" % (card_base64,)) + if not rsp.startswith("200 "): + logging.info("Rejected card base64:%s" % (card_base64,)) + return False + username = rsp.split('=')[1].strip() + logging.info("Accepted card base64:%s for %s" % (card_base64,username,)) - # Check for thier username - try: - # Get info from the system (by UID) - info = pwd.getpwuid(self._userid) - except KeyError: - logging.info('getting info for uid %d: user not in password file' % (self._userid,)) - return False - self._username = info.pw_name + ## Get UID for the username (not needed?) + #try: + # # Get info from the system (by username) + # info = pwd.getpwnam(username) + #except KeyError: + # logging.info('getting info for user \'%s\': user not in password file' % (username,)) + # return False + #self._userid = info.pw_uid + self._userid = None + self._username = username # If we get this far all is good self._loggedIn = True @@ -176,34 +177,22 @@ class OpenDispense(DispenseInterface): def addCard(self, cardId): if not self.isLoggedIn(): return False - if DISPSRV_MIFARE: - card_base64 = base64.b64encode(cardId) - if card_base64 in CARD_BLACKLIST: - logging.info("Blacklisted card base64:%s" % (card_base64,)) - return False - logging.info('Enrolling card base64:%s to uid %s (%s)' % (card_base64, self._userId, self._username)) - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - sock.connect(DISPENSE_ENDPOINT) - sockf = sock.makefile() - sockf.write("AUTHIDENT\n") - sockf.flush(); rsp = sockf.readline() - assert "200" in rsp - sockf.write("SETEUSER %s\n" % (self._username,)) - sockf.flush(); rsp = sockf.readline() - assert "200" in rsp - sockf.write("CARD_ADD %s\n" % (card_base64,)) - sockf.flush(); rsp = sockf.readline() - if "200" in rsp: - return True - else: - return False + + card_base64 = base64.b64encode(cardId) + if card_base64 in CARD_BLACKLIST: + logging.info("Blacklisted card base64:%s" % (card_base64,)) + return False + logging.info('Enrolling card base64:%s to uid %s (%s)' % (card_base64, self._userId, self._username)) + conn = self._connect(set_euid=True) + if conn is None: + logging.warn("Enrolling card failed: Unable to connect".format(rsp)) + return False + rsp = conn.send_command("CARD_ADD %s" % (card_base64,)) + if "200" in rsp: + return True else: - if get_uid(cardId) != None: - return False - else: - logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username)) - set_card_id(self._userId, cardId) - return True + logging.warn("Enrolling card failed: Response = {}".format(rsp)) + return False def isLoggedIn(self): return self._loggedIn @@ -214,7 +203,7 @@ class OpenDispense(DispenseInterface): def getBalance(self): # Balance checking if self.isLoggedIn(): - acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate() + acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE, encoding='utf-8').communicate() else: return None balance = acct[acct.find("$")+1:acct.find("(")].strip() @@ -224,7 +213,7 @@ class OpenDispense(DispenseInterface): logging.debug("getItemInfo(%s)" % (itemId,)) itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId) args = ('dispense', 'iteminfo', itemId) - info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate() + info, unused = Popen(args, close_fds=True, stdout=PIPE, encoding='utf-8').communicate() m = re.match("\s*[a-z]+:\d+\s+(\d+)\.(\d\d)\s+([^\n]+)", info) if m == None: return("dead", 0) @@ -243,11 +232,14 @@ class OpenDispense(DispenseInterface): #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 +class Connection(object): + def __init__(self, sockf): + self.sockf = sockf + def send_command(self, command): + self.sockf.write(command) + self.sockf.write("\n") + self.sockf.flush() + return self.sockf.readline() """ This class abstracts the idea of item numbers. diff --git a/VendServer/VendServer.py b/VendServer/VendServer.py index dda160bc3c7c59220ca697edb835dfbedbb92259..46b31418523f2264be1a94f781fe81253bc150a6 100755 --- a/VendServer/VendServer.py +++ b/VendServer/VendServer.py @@ -9,7 +9,7 @@ import logging, logging.handlers from traceback import format_tb from time import time, sleep, mktime, localtime from subprocess import Popen, PIPE -from .LATClient import LATClient, LATClientException +#from .LATClient import LATClient, LATClientException from .SerialClient import SerialClient, SerialClientException from .VendingMachine import VendingMachine, VendingException from .MessageKeeper import MessageKeeper @@ -200,7 +200,7 @@ class VendServer(): """ def center(self, str): LEN = 10 - return ' '*((LEN-len(str))/2)+str + return ' '*((LEN-len(str))//2)+str """ Configure the things that will appear on screen whil the machine is idling. @@ -645,16 +645,16 @@ class VendServer(): ### 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]]) + 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]]) + 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 @@ -923,7 +923,7 @@ Connect to the machine. """ def connect_to_vend(options, cf): - if options.use_lat: + if False and options.use_lat: 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() @@ -965,6 +965,7 @@ def parse_args(): op.add_option('-q', '--quiet', dest='quiet', action='store_true', default=False, help='only report errors') op.add_option('--pid-file', dest='pid_file', metavar='FILE', default='', help='store daemon\'s pid in the given file') op.add_option('--traceback-file', dest='traceback_file', default='', help='destination to print tracebacks when receiving SIGUSR1') + op.add_option('--crash', action='store_true', help="Crash immediately instead of looping") options, args = op.parse_args() if len(args) != 0: @@ -1082,6 +1083,8 @@ def main(argv=None): except SystemExit: break except: + if options.crash: + raise (exc_type, exc_value, exc_traceback) = sys.exc_info() tb = format_tb(exc_traceback, 20) del exc_traceback