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):
75 self._loggedIn = False
78 card_base64 = base64.b64encode(cardId)
80 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
81 sock.connect(DISPENSE_ENDPOINT)
82 logging.debug('connected to dispsrv')
83 sockf = sock.makefile()
84 sockf.write("AUTHIDENT\n"); sockf.flush()
85 rsp = sockf.readline()
87 logging.debug('authenticated')
88 sockf.write("AUTHCARD %s\n" % (card_base64,)); sockf.flush()
89 rsp = sockf.readline()
92 username = rsp.split('=')[1].strip()
94 # Check for thier username
96 # Get info from the system (by username)
97 info = pwd.getpwnam(username)
99 logging.info('getting info for user \'%s\': user not in password file' % (username,))
103 self._userid = get_uid(cardId)
105 # Check for thier username
107 # Get info from the system (by UID)
108 info = pwd.getpwuid(self._userid)
110 logging.info('getting info for uid %d: user not in password file' % (self._userid,))
113 # If we get this far all is good
114 self._loggedIn = True
115 self._disabled = False
116 self._userid = info.pw_uid
117 self._username = info.pw_name
120 def addCard(self, cardId):
121 if not self.isLoggedIn():
124 card_base64 = base64.b64encode(cardId)
125 logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
126 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
127 sock.connect(DISPENSE_ENDPOINT)
128 sockf = sock.makefile()
129 sockf.write("AUTHIDENT\n")
130 sockf.flush(); rsp = sockf.readline()
132 sockf.write("SETEUSER %s\n" % (self._username,))
133 sockf.flush(); rsp = sockf.readline()
135 sockf.write("CARD_ADD %s\n" % (card_base64,))
136 sockf.flush(); rsp = sockf.readline()
142 if get_uid(cardId) != None:
145 logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
146 set_card_id(self._userId, cardId)
149 def isLoggedIn(self):
150 return self._loggedIn
152 def getUsername(self):
153 return self._username
155 def getBalance(self):
157 if self.isLoggedIn():
158 acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate()
161 balance = acct[acct.find("$")+1:acct.find("(")].strip()
164 def getItemInfo(self, itemId):
165 logging.debug("getItemInfo(%s)" % (itemId,))
166 itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId)
167 args = ('dispense', 'iteminfo', itemId)
168 info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate()
169 m = re.match("\s*[a-z]+:\d+\s+(\d+)\.(\d\d)\s+([^\n]+)", info)
172 cents = int(m.group(1))*100 + int(m.group(2))
173 # return (name, price in cents)
174 return (m.group(3), cents)
176 def isDisabled(self):
177 return self._disabled
179 def dispenseItem(self, itemId):
180 if not self.isLoggedIn() or self.getItemInfo(itemId)[0] == "dead":
183 print('dispense -u "%s" %s'%(self._username, itemId))
184 #os.system('dispense -u "%s" %s'%(self._username, itemId))
189 self._disabled = True
190 self._loggedIn = False
194 This class abstracts the idea of item numbers.
195 It removes the need for VendServer to know the mappings between inputted numbers
196 and the equivalent itemId in OpenDispense.
198 class OpenDispenseMapping():
201 def vendingMachineToOpenDispense(itemId):
202 logging.debug("vendingMachineToOpenDispense(%s)" % (itemId,))
203 _mappingFile = "OpenDispenseMappings.conf"
205 fh = open(_mappingFile)
208 return 'coke:' + itemId[0]
209 elif itemId[1] == '5':
215 return 'snack:' + itemId
219 if line.startswith(str(itemId) + " "):
220 map = line[len(str(itemId)) + 1:].strip()