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
15 from subprocess import Popen, PIPE
16 from LDAPConnector import get_uid,get_uname, set_card_id
18 DISPENSE_ENDPOINT = ("localhost", 11020)
21 class OpenDispense(DispenseInterface):
27 def __init__(self, username=None, secret=False):
30 def authUserIdPin(self, userId, pin):
35 info = pwd.getpwuid(userId)
37 logging.info('getting pin for uid %d: user not in password file'%userId)
40 if info.pw_dir == None: return False
41 pinfile = os.path.join(info.pw_dir, '.pin')
45 logging.info('getting pin for uid %d: .pin not found in home directory'%userId)
48 logging.info('getting pin for uid %d: .pin has wrong permissions. Fixing.'%userId)
49 os.chmod(pinfile, 0600)
53 logging.info('getting pin for uid %d: I cannot read pin file'%userId)
55 pinstr = f.readline().strip()
57 if not re.search('^[0-9]{4}$', pinstr):
58 logging.info('getting pin for uid %d: %s not a good pin'%(userId,repr(pinstr)))
61 if pinstr == str(pin):
65 self._disabled = False
66 self._username = info.pw_name
72 def authMifareCard(self, cardId):
74 card_base64 = base64.b64encode(cardId)
76 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
77 sock.connect(DISPENSE_ENDPOINT)
78 sock.write("AUTHIDENT\n")
81 sock.write("AUTHCARD %s\n" % (card_base64,))
84 raise ValueError, "no UID found for card ID"
85 username = rsp.split('=')[1]
87 # Check for thier username
89 # Get info from the system (by username)
90 info = pwd.getpwnam(username)
92 logging.info('getting pin for uid %d: user not in password file'%uid)
96 self._userid = get_uid(cardId)
98 # Check for thier username
100 # Get info from the system (by UID)
101 info = pwd.getpwuid(self._userid)
103 logging.info('getting pin for uid %d: user not in password file'%uid)
106 # If we get this far all is good
107 self._loggedIn = True
108 self._disabled = False
109 self._userid = info.pw_uid
110 self._username = info.pw_name
113 def addCard(self, cardId):
114 if not self.isLoggedIn():
117 card_base64 = base64.b64encode(cardId)
118 logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
119 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
120 sock.connect(DISPENSE_ENDPOINT)
121 sock.write("AUTHIDENT\n")
122 rsp = sock.readline()
124 sock.write("SETEUSER %s\n", self._username)
125 rsp = sock.readline()
127 sock.write("CARD_ADD %s\n", card_base64)
128 rsp = sock.readline()
134 if get_uid(cardId) != None:
137 logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
138 set_card_id(self._userId, cardId)
141 def isLoggedIn(self):
142 return self._loggedIn
144 def getUsername(self):
145 return self._username
147 def getBalance(self):
149 if self.isLoggedIn():
150 acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate()
153 balance = acct[acct.find("$")+1:acct.find("(")].strip()
156 def getItemInfo(self, itemId):
157 itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId)
158 args = ('dispense', 'iteminfo', itemId)
159 info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate()
160 m = re.match("\s*[a-z]+:\d+\s+(\d+)\.(\d\d)\s+([^\n]+)", info)
163 cents = int(m.group(1))*100 + int(m.group(2))
164 # return (name, price in cents)
165 return (m.group(3), cents)
167 def isDisabled(self):
168 return self._disabled
170 def dispenseItem(self, itemId):
171 if not self.isLoggedIn() or self.getItemInfo(itemId)[0] == "dead":
174 print('dispense -u "%s" %s'%(self._username, itemId))
175 #os.system('dispense -u "%s" %s'%(self._username, itemId))
180 self._disabled = True
181 self._loggedIn = False
185 This class abstracts the idea of item numbers.
186 It removes the need for VendServer to know the mappings between inputted numbers
187 and the equivalent itemId in OpenDispense.
189 class OpenDispenseMapping():
192 def vendingMachineToOpenDispense(itemId):
193 _mappingFile = "OpenDispenseMappings.conf"
194 fh = open(_mappingFile)
198 if line.startswith(str(itemId) + " "):
199 map = line[len(str(itemId)) + 1:].strip()