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()
91 logging.info("Rejected card base64:%s" % (card_base64,))
93 username = rsp.split('=')[1].strip()
94 logging.info("Accepted card base64:%s for %s" % (card_base64,username,))
96 # Check for thier username
98 # Get info from the system (by username)
99 info = pwd.getpwnam(username)
101 logging.info('getting info for user \'%s\': user not in password file' % (username,))
105 self._userid = get_uid(cardId)
107 # Check for thier username
109 # Get info from the system (by UID)
110 info = pwd.getpwuid(self._userid)
112 logging.info('getting info for uid %d: user not in password file' % (self._userid,))
115 # If we get this far all is good
116 self._loggedIn = True
117 self._disabled = False
118 self._userid = info.pw_uid
119 self._username = info.pw_name
122 self._loggedIn = False
123 self._disabled = False
125 self._username = None
127 def addCard(self, cardId):
128 if not self.isLoggedIn():
131 card_base64 = base64.b64encode(cardId)
132 logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
133 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
134 sock.connect(DISPENSE_ENDPOINT)
135 sockf = sock.makefile()
136 sockf.write("AUTHIDENT\n")
137 sockf.flush(); rsp = sockf.readline()
139 sockf.write("SETEUSER %s\n" % (self._username,))
140 sockf.flush(); rsp = sockf.readline()
142 sockf.write("CARD_ADD %s\n" % (card_base64,))
143 sockf.flush(); rsp = sockf.readline()
149 if get_uid(cardId) != None:
152 logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
153 set_card_id(self._userId, cardId)
156 def isLoggedIn(self):
157 return self._loggedIn
159 def getUsername(self):
160 return self._username
162 def getBalance(self):
164 if self.isLoggedIn():
165 acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate()
168 balance = acct[acct.find("$")+1:acct.find("(")].strip()
171 def getItemInfo(self, itemId):
172 logging.debug("getItemInfo(%s)" % (itemId,))
173 itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId)
174 args = ('dispense', 'iteminfo', itemId)
175 info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate()
176 m = re.match("\s*[a-z]+:\d+\s+(\d+)\.(\d\d)\s+([^\n]+)", info)
179 cents = int(m.group(1))*100 + int(m.group(2))
180 # return (name, price in cents)
181 return (m.group(3), cents)
183 def isDisabled(self):
184 return self._disabled
186 def dispenseItem(self, itemId):
187 if not self.isLoggedIn() or self.getItemInfo(itemId)[0] == "dead":
190 print('dispense -u "%s" %s'%(self._username, itemId))
191 #os.system('dispense -u "%s" %s'%(self._username, itemId))
196 self._disabled = True
197 self._loggedIn = False
201 This class abstracts the idea of item numbers.
202 It removes the need for VendServer to know the mappings between inputted numbers
203 and the equivalent itemId in OpenDispense.
205 class OpenDispenseMapping():
208 def vendingMachineToOpenDispense(itemId):
209 logging.debug("vendingMachineToOpenDispense(%s)" % (itemId,))
210 _mappingFile = "OpenDispenseMappings.conf"
212 fh = open(_mappingFile)
215 return 'coke:' + itemId[0]
216 elif itemId[1] == '5':
222 return 'snack:' + itemId
226 if line.startswith(str(itemId) + " "):
227 map = line[len(str(itemId)) + 1:].strip()