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 self._loggedIn = False
121 self._disabled = False
123 self._username = None
125 def addCard(self, cardId):
126 if not self.isLoggedIn():
129 card_base64 = base64.b64encode(cardId)
130 logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
131 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
132 sock.connect(DISPENSE_ENDPOINT)
133 sockf = sock.makefile()
134 sockf.write("AUTHIDENT\n")
135 sockf.flush(); rsp = sockf.readline()
137 sockf.write("SETEUSER %s\n" % (self._username,))
138 sockf.flush(); rsp = sockf.readline()
140 sockf.write("CARD_ADD %s\n" % (card_base64,))
141 sockf.flush(); rsp = sockf.readline()
147 if get_uid(cardId) != None:
150 logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
151 set_card_id(self._userId, cardId)
154 def isLoggedIn(self):
155 return self._loggedIn
157 def getUsername(self):
158 return self._username
160 def getBalance(self):
162 if self.isLoggedIn():
163 acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate()
166 balance = acct[acct.find("$")+1:acct.find("(")].strip()
169 def getItemInfo(self, itemId):
170 logging.debug("getItemInfo(%s)" % (itemId,))
171 itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId)
172 args = ('dispense', 'iteminfo', itemId)
173 info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate()
174 m = re.match("\s*[a-z]+:\d+\s+(\d+)\.(\d\d)\s+([^\n]+)", info)
177 cents = int(m.group(1))*100 + int(m.group(2))
178 # return (name, price in cents)
179 return (m.group(3), cents)
181 def isDisabled(self):
182 return self._disabled
184 def dispenseItem(self, itemId):
185 if not self.isLoggedIn() or self.getItemInfo(itemId)[0] == "dead":
188 print('dispense -u "%s" %s'%(self._username, itemId))
189 #os.system('dispense -u "%s" %s'%(self._username, itemId))
194 self._disabled = True
195 self._loggedIn = False
199 This class abstracts the idea of item numbers.
200 It removes the need for VendServer to know the mappings between inputted numbers
201 and the equivalent itemId in OpenDispense.
203 class OpenDispenseMapping():
206 def vendingMachineToOpenDispense(itemId):
207 logging.debug("vendingMachineToOpenDispense(%s)" % (itemId,))
208 _mappingFile = "OpenDispenseMappings.conf"
210 fh = open(_mappingFile)
213 return 'coke:' + itemId[0]
214 elif itemId[1] == '5':
220 return 'snack:' + itemId
224 if line.startswith(str(itemId) + " "):
225 map = line[len(str(itemId)) + 1:].strip()