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):
33 return self.authUserIdPin_db(userId, pin)
34 #return self.authUserIdPin_file(userId, pin)
36 def authUserIdPin_db(self, userId, pin):
40 # Get username (TODO: Store the user ID in the dispense database too)
41 info = pwd.getpwuid(userId)
43 logging.info('getting pin for uid %d: user not in password file'%userId)
46 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
47 sock.connect(DISPENSE_ENDPOINT)
48 logging.debug('connected to dispsrv')
49 sockf = sock.makefile()
50 sockf.write("AUTHIDENT\n"); sockf.flush()
51 rsp = sockf.readline()
53 logging.debug('authenticated')
54 sockf.write("PIN_CHECK %s %s\n" % (info.pw_name, pin)); sockf.flush()
55 rsp = sockf.readline()
57 logging.info('checking pin for uid %d: Server said no - %r' % (userId, rsp))
60 logging.info('accepted pin for uid %d \'%s\'' % (userId, info.pw_name))
63 self._disabled = False
64 self._username = info.pw_name
67 def authUserIdPin_file(self, userId, pin):
72 info = pwd.getpwuid(userId)
74 logging.info('getting pin for uid %d: user not in password file'%userId)
77 if info.pw_dir == None: return False
78 pinfile = os.path.join(info.pw_dir, '.pin')
82 logging.info('getting pin for uid %d: .pin not found in home directory'%userId)
85 logging.info('getting pin for uid %d: .pin has wrong permissions. Fixing.'%userId)
86 os.chmod(pinfile, 0600)
90 logging.info('getting pin for uid %d: I cannot read pin file'%userId)
92 pinstr = f.readline().strip()
94 if not re.search('^[0-9]{4}$', pinstr):
95 logging.info('getting pin for uid %d: %s not a good pin'%(userId,repr(pinstr)))
98 if pinstr == str(pin):
100 self._userid = userId
101 self._loggedIn = True
102 self._disabled = False
103 self._username = info.pw_name
109 def authMifareCard(self, cardId):
110 self._loggedIn = False
111 self._username = None
113 card_base64 = base64.b64encode(cardId)
115 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
116 sock.connect(DISPENSE_ENDPOINT)
117 logging.debug('connected to dispsrv')
118 sockf = sock.makefile()
119 sockf.write("AUTHIDENT\n"); sockf.flush()
120 rsp = sockf.readline()
122 logging.debug('authenticated')
123 sockf.write("AUTHCARD %s\n" % (card_base64,)); sockf.flush()
124 rsp = sockf.readline()
126 logging.info("Rejected card base64:%s" % (card_base64,))
128 username = rsp.split('=')[1].strip()
129 logging.info("Accepted card base64:%s for %s" % (card_base64,username,))
131 # Check for thier username
133 # Get info from the system (by username)
134 info = pwd.getpwnam(username)
136 logging.info('getting info for user \'%s\': user not in password file' % (username,))
140 self._userid = get_uid(cardId)
142 # Check for thier username
144 # Get info from the system (by UID)
145 info = pwd.getpwuid(self._userid)
147 logging.info('getting info for uid %d: user not in password file' % (self._userid,))
150 # If we get this far all is good
151 self._loggedIn = True
152 self._disabled = False
153 self._userid = info.pw_uid
154 self._username = info.pw_name
157 self._loggedIn = False
158 self._disabled = False
160 self._username = None
162 def addCard(self, cardId):
163 if not self.isLoggedIn():
166 card_base64 = base64.b64encode(cardId)
167 logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
168 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
169 sock.connect(DISPENSE_ENDPOINT)
170 sockf = sock.makefile()
171 sockf.write("AUTHIDENT\n")
172 sockf.flush(); rsp = sockf.readline()
174 sockf.write("SETEUSER %s\n" % (self._username,))
175 sockf.flush(); rsp = sockf.readline()
177 sockf.write("CARD_ADD %s\n" % (card_base64,))
178 sockf.flush(); rsp = sockf.readline()
184 if get_uid(cardId) != None:
187 logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
188 set_card_id(self._userId, cardId)
191 def isLoggedIn(self):
192 return self._loggedIn
194 def getUsername(self):
195 return self._username
197 def getBalance(self):
199 if self.isLoggedIn():
200 acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate()
203 balance = acct[acct.find("$")+1:acct.find("(")].strip()
206 def getItemInfo(self, itemId):
207 logging.debug("getItemInfo(%s)" % (itemId,))
208 itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId)
209 args = ('dispense', 'iteminfo', itemId)
210 info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate()
211 m = re.match("\s*[a-z]+:\d+\s+(\d+)\.(\d\d)\s+([^\n]+)", info)
214 cents = int(m.group(1))*100 + int(m.group(2))
215 # return (name, price in cents)
216 return (m.group(3), cents)
218 def isDisabled(self):
219 return self._disabled
221 def dispenseItem(self, itemId):
222 if not self.isLoggedIn() or self.getItemInfo(itemId)[0] == "dead":
225 print('dispense -u "%s" %s'%(self._username, itemId))
226 #os.system('dispense -u "%s" %s'%(self._username, itemId))
231 self._disabled = True
232 self._loggedIn = False
236 This class abstracts the idea of item numbers.
237 It removes the need for VendServer to know the mappings between inputted numbers
238 and the equivalent itemId in OpenDispense.
240 class OpenDispenseMapping():
243 def vendingMachineToOpenDispense(itemId):
244 logging.debug("vendingMachineToOpenDispense(%s)" % (itemId,))
245 _mappingFile = "OpenDispenseMappings.conf"
247 fh = open(_mappingFile)
250 return 'coke:' + itemId[0]
251 elif itemId[1] == '5':
257 return 'snack:' + itemId
261 if line.startswith(str(itemId) + " "):
262 map = line[len(str(itemId)) + 1:].strip()