2 Author: Mitchell Pomery (bobgeorge33)
4 System to connect to OpenDispense2.
5 Most of this code has been copied out of VendServer.py, then had variables updated so that it runs.
6 This is so VendServer can easily operate regardless of the current accounting backend.
7 Documentation for this code can be found inder Dispence.DispenceInterface
10 from DispenseInterface import DispenseInterface
17 from subprocess import Popen, PIPE
18 from LDAPConnector import get_uid,get_uname, set_card_id
20 DISPENSE_ENDPOINT = ("localhost", 11020)
23 class OpenDispense(DispenseInterface):
29 def __init__(self, username=None, secret=False):
32 def authUserIdPin(self, userId, pin):
37 info = pwd.getpwuid(userId)
39 logging.info('getting pin for uid %d: user not in password file'%userId)
42 if info.pw_dir == None: return False
43 pinfile = os.path.join(info.pw_dir, '.pin')
47 logging.info('getting pin for uid %d: .pin not found in home directory'%userId)
50 logging.info('getting pin for uid %d: .pin has wrong permissions. Fixing.'%userId)
51 os.chmod(pinfile, 0600)
55 logging.info('getting pin for uid %d: I cannot read pin file'%userId)
57 pinstr = f.readline().strip()
59 if not re.search('^[0-9]{4}$', pinstr):
60 logging.info('getting pin for uid %d: %s not a good pin'%(userId,repr(pinstr)))
63 if pinstr == str(pin):
67 self._disabled = False
68 self._username = info.pw_name
74 def authMifareCard(self, cardId):
76 card_base64 = base64.b64encode(cardId)
78 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
79 sock.connect(DISPENSE_ENDPOINT)
80 logging.debug('connected to dispsrv')
81 sockf = sock.makefile()
82 sockf.write("AUTHIDENT\n"); sockf.flush()
83 rsp = sockf.readline()
85 logging.debug('authenticated')
86 sockf.write("AUTHCARD %s\n" % (card_base64,)); sockf.flush()
87 rsp = sockf.readline()
89 raise ValueError, "no UID found for card ID"
90 username = rsp.split('=')[1].strip()
92 # Check for thier username
94 # Get info from the system (by username)
95 info = pwd.getpwnam(username)
97 logging.info('getting info for user \'%s\': user not in password file' % (username,))
101 self._userid = get_uid(cardId)
103 # Check for thier username
105 # Get info from the system (by UID)
106 info = pwd.getpwuid(self._userid)
108 logging.info('getting info for uid %d: user not in password file' % (self._userid,))
111 # If we get this far all is good
112 self._loggedIn = True
113 self._disabled = False
114 self._userid = info.pw_uid
115 self._username = info.pw_name
118 def addCard(self, cardId):
119 if not self.isLoggedIn():
122 card_base64 = base64.b64encode(cardId)
123 logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
124 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
125 sock.connect(DISPENSE_ENDPOINT)
126 sockf = sock.makefile()
127 sockf.write("AUTHIDENT\n")
128 sockf.flush(); rsp = sockf.readline()
130 sockf.write("SETEUSER %s\n", self._username)
131 sockf.flush(); rsp = sockf.readline()
133 sockf.write("CARD_ADD %s\n", card_base64)
134 sockf.flush(); rsp = sockf.readline()
140 if get_uid(cardId) != None:
143 logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
144 set_card_id(self._userId, cardId)
147 def isLoggedIn(self):
148 return self._loggedIn
150 def getUsername(self):
151 return self._username
153 def getBalance(self):
155 if self.isLoggedIn():
156 acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate()
159 balance = acct[acct.find("$")+1:acct.find("(")].strip()
162 def getItemInfo(self, itemId):
163 logging.debug("getItemInfo(%s)" % (itemId,))
164 itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId)
165 args = ('dispense', 'iteminfo', itemId)
166 info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate()
167 m = re.match("\s*[a-z]+:\d+\s+(\d+)\.(\d\d)\s+([^\n]+)", info)
170 cents = int(m.group(1))*100 + int(m.group(2))
171 # return (name, price in cents)
172 return (m.group(3), cents)
174 def isDisabled(self):
175 return self._disabled
177 def dispenseItem(self, itemId):
178 if not self.isLoggedIn() or self.getItemInfo(itemId)[0] == "dead":
181 print('dispense -u "%s" %s'%(self._username, itemId))
182 #os.system('dispense -u "%s" %s'%(self._username, itemId))
187 self._disabled = True
188 self._loggedIn = False
192 This class abstracts the idea of item numbers.
193 It removes the need for VendServer to know the mappings between inputted numbers
194 and the equivalent itemId in OpenDispense.
196 class OpenDispenseMapping():
199 def vendingMachineToOpenDispense(itemId):
200 logging.debug("vendingMachineToOpenDispense(%s)" % (itemId,))
201 _mappingFile = "OpenDispenseMappings.conf"
203 fh = open(_mappingFile)
206 return 'coke:' + itemId[0]
207 elif itemId[1] == '5':
213 return 'snack:' + itemId
217 if line.startswith(str(itemId) + " "):
218 map = line[len(str(itemId)) + 1:].strip()