fortune Idler
[uccvend-vendserver.git] / virtualvend / vvend.py
1 #!/usr/bin/env python
2
3 import sys
4 import socket
5 import string
6
7 try:
8   import pygtk
9   #tell pyGTK, if possible, that we want GTKv2
10   pygtk.require("2.0")
11 except:
12   #Some distributions come with GTK2, but not pyGTK
13   pass
14
15 try:
16   import gtk
17   import gtk.glade
18 except:
19   print "You need to install pyGTK or GTKv2 ",
20   print "or set your PYTHONPATH correctly."
21   print "try: export PYTHONPATH=",
22   print "/usr/local/lib/python2.2/site-packages/"
23   sys.exit(1)
24
25 import pango
26
27 class Switches:
28     def __init__(self):
29         self.misc_input = 0xff
30         self.switch_input = 0x3f
31     def door_open(self):
32         return self.switch_input & 0x20
33     def set_door_open(self, open = True):
34         if open:
35             self.switch_input |= 0x20
36         else:
37             self.switch_input &= ~0x20
38
39 #now we have both gtk and gtk.glade imported
40 #Also, we know we are running GTK v2
41
42 class appgui:
43   def __init__(self):
44     """
45     In this init we are going to display the main
46     serverinfo window
47     """
48     gladefile="vvend.glade"
49     windowname="vvend"
50     self.wTree=gtk.glade.XML (gladefile,windowname)
51     # we only have two callbacks to register, but
52     # you could register any number, or use a
53     # special class that automatically
54     # registers all callbacks. If you wanted to pass
55     # an argument, you would use a tuple like this:
56     # dic = { "on button1_clicked" : 
57     #         (self.button1_clicked, arg1,arg2) , ...
58     
59     dic = { 
60         "on_button1_clicked" : self.keypad_clicked,
61         "on_button2_clicked" : self.keypad_clicked,
62         "on_button3_clicked" : self.keypad_clicked,
63         "on_button4_clicked" : self.keypad_clicked,
64         "on_button5_clicked" : self.keypad_clicked,
65         "on_button6_clicked" : self.keypad_clicked,
66         "on_button7_clicked" : self.keypad_clicked,
67         "on_button8_clicked" : self.keypad_clicked,
68         "on_button9_clicked" : self.keypad_clicked,
69         "on_button10_clicked" : self.keypad_clicked,
70         "on_button11_clicked" : self.keypad_clicked,
71         "on_button11_clicked" : self.keypad_clicked,
72         "on_door_toggled" : self.door_changed,
73         "on_vvend_destroy_event" : self.quit,
74         "on_vvend_delete_event" : self.quit }
75     self.wTree.signal_autoconnect (dic)
76     display = self.wTree.get_widget("label1")
77     label_font = pango.FontDescription('monospace 28')
78     display.modify_font(label_font)
79
80     label_style = display.get_style().copy()
81     fg_color = display.get_colormap().alloc_color('lightgreen')
82     label_style.fg[gtk.STATE_NORMAL] = fg_color
83     display.set_style(label_style)
84
85     w = self.wTree.get_widget("eventbox1")
86     wstyle = w.get_style().copy()
87     bg_color = w.get_colormap().alloc_color('black')
88     wstyle.bg[gtk.STATE_NORMAL] = bg_color
89     w.set_style(wstyle)
90
91     display.set_text("*5N4CK0RZ*")
92
93     # vending machine password set here
94     self.vendpw = "AAAAAAAAAAAAAAAA"
95
96     self.messageid = None
97     self.switches = Switches()
98
99     #s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
100     #s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
101 #
102 #    listenhost=""
103 #    listenport=5150
104 #    s.bind((listenhost, listenport))
105 #    # only one connection
106 #    s.listen(1)
107 #    s.setblocking(1)
108 #    #GDK->gtk.gdk in GTK V 2.0
109 #    id=gtk.input_add(s, gtk.gdk.INPUT_READ, self.handleNewConnection)
110
111     self.server()
112
113
114     return
115
116     def __del__(self):
117         try:
118             self.sock.close()
119             self.sock.shutdown()
120         except:
121             pass
122
123 #####CALLBACKS
124   def keypad_clicked(self,widget):
125     key = widget.get_label()
126     if key == 'RESET':
127         key = '11'
128     else:
129         key = '0'+key
130     self.do_send('2'+key+' keypress\n')
131
132   def door_changed(self, widget):
133     self.switches.set_door_open(not widget.get_active())
134     if widget.get_active():
135         self.do_send('401 door closed\n')
136     else:
137         self.do_send('400 door open\n')
138
139   def handleNewConnection(self,source,condition):
140     #source is a socket in GTK v 1 and a fd in version 2
141     conn, addr = source.accept()
142     sys.stdout.write(conn.recv(1))
143     conn.send("bing\n")
144     return gtk.TRUE
145
146 # from http://www.pythonbrasil.com.br/moin.cgi/MonitorandoSocketsComPygtk
147
148
149   def send(self, data=None, widget=None):
150      text = self.entry.get_text()
151      self.do_send(text)
152      self.entry.set_text('')
153
154      #
155
156   def do_send(self, data):
157
158      # envia ''data'' para todos os clientes conectados
159
160      for addr, (conn, tag) in self.clients.iteritems():
161             conn.send(data)
162
163   def server(self):
164
165      # inicializa o servidor
166      port = 5150
167
168      self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
169      self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
170      self.sock.bind(('localhost', port))
171      self.sock.listen(0)
172      print "listening on ", port
173
174      # 
175      #
176
177      self.server_tag = gtk.input_add(self.sock, gtk.gdk.INPUT_READ, self.accept)
178
179      # mantemos uma lista dos clientes conectados
180
181      self.clients = {}
182
183   def accept(self, source, condition):
184
185      #
186      # esperando para ser aceito
187
188      conn, addr = source.accept()
189      self.insert("%s:%s conectado\n" % addr)
190
191      # insere o cliente na lista e registra o método self.write como 
192      # callback para quando existirem dados esperando para serem lidos
193
194      self.do_prompt()
195      self.clients[addr] = (conn, gtk.input_add(conn, gtk.gdk.INPUT_READ, self.write))
196
197   def write(self, source, condition):
198
199      # método chamado quando um cliente envia dados 
200
201      data = source.recv(1024)
202      if data.strip() == 'bye' or not len(data):
203
204             # se o cliente enviar um ''bye'', desconecte-o :)
205
206             source.close()
207             for addr, (conn, tag) in self.clients.iteritems():
208                 if source is conn:
209                     gtk.input_remove(tag)
210                     self.insert('%s:%s desconectado\n' % addr)
211                     del self.clients[addr]
212                     
213                     self.server_tag = gtk.input_add(self.sock, gtk.gdk.INPUT_READ, self.accept)
214                     break
215      elif data.strip() == 'quit':
216         self.quit()
217      else:
218             for (addr, port), (conn, tag) in self.clients.iteritems():
219                 if source is conn:
220                     self.insert('%s:%s >>> %s\n'%(addr, port, data.strip()))
221                     self.handle_command(data.strip())
222                     break
223      
224      return gtk.TRUE
225
226   def insert(self, data):
227      statusbar = self.wTree.get_widget("statusbar1")
228      if self.messageid:
229         statusbar.remove(1, self.messageid)
230      self.messageid=statusbar.push(1,data)
231
232   def quit(self, *args):
233      sys.stdout.write("quiting...\n")
234      gtk.input_remove(self.server_tag)
235      for addr, (conn, tag) in self.clients.iteritems():
236             gtk.input_remove(tag)
237             conn.close()
238      self.sock.close()
239      self.sock.shutdown()
240
241      gtk.mainquit()
242      sys.stdout.write("quit!\n")
243
244   def do_prompt(self):
245     self.do_send("# ")
246
247   def do_help(self):
248     help = """
249
250 Valid commands are:
251  ABOUT         ROM information
252  B[S][nn]      beep [synchronously] for a duration nn (optional)
253  C[S][nn]      silence [synchronously] for a duration nn (optional)
254  Dxxxxxxxxxx   show a message on the display
255  ECHO {ON|OFF} turn echo on or off
256  GETROM        download the ROM source code using xmodem
257  H[...]        this help screen
258 *JUMPxxxx      jumps to a subroutine at location xxxx
259 *PEEKxxxx      returns the value of the byte at location xxxx
260 *POKExxxxyy    sets the value of location xxxx to yy
261  PING          pongs
262  S[...]        query all internal switch states
263 +Vnn           vend an item
264 +VALL          vend all items
265 *Wxxxxxxxxxxxx set a new password for authenticated vends. xxx=16 chars
266                password will be converted to uppercase
267
268 Very few functions are available when the machine is in standalone 
269 mode (DIP SW 1 is set)
270 + denotes that this item requires authentication if DIP SW 2 is set
271 * denotes that DIP SW 3 must be set to use these
272 Commands starting with # are ignored (comments)
273 """
274     self.do_send(help)
275   
276   def do_about(self):
277     about = """
278
279 The Virtual Vending Machine Company
280
281 Mark Tearle, June 2004
282 """
283     self.do_send(about)
284
285   def do_vend_all(self):
286      for i in range(11,99):
287         self.do_send("101 Vending "+str(i)+"\n")
288         self.do_send("153 Home sensors failing\n")
289      self.do_send("102 Vend all motors complete\n")
290   
291   def do_vend(self,command):
292      fail = None
293      if fail:
294         self.do_send("153 Home sensors failing\n")
295      else:
296         self.insert("Vending "+command)
297         self.do_send("100 Vend successful\n")
298     
299   def do_display(self,string):
300      display = self.wTree.get_widget("label1")
301      display.set_text("%-10.10s" % (string))
302      self.do_send('300 Written\n')
303
304   def do_beep(self,command):
305      sys.stdout.write("\a")
306      self.do_send('500 Beeped\n')
307
308   def do_silence(self,command):
309      pass
310
311   def do_switches(self):
312      self.do_send("600 3F 3F\n")
313
314   def do_pong(self):
315      self.do_send("000 PONG!\n")
316
317   def handle_command(self, command):
318      command = string.upper(command)
319      print command
320      if string.find(command, "HELP",0) == 0:
321         self.do_help()
322      elif string.find(command, "ABOUT",0) == 0:
323         self.do_about()
324      elif string.find(command, "PING",0) == 0:
325         self.do_pong()
326      elif string.find(command, "VALL",0) == 0:
327         self.do_vend_all()
328      elif string.find(command, "V",0) == 0:
329         self.do_vend(command)
330      elif string.find(command, "B",0) == 0:
331         self.do_beep(command)
332      elif string.find(command, "C",0) == 0:
333         self.do_silence(command)
334      elif string.find(command, "S",0) == 0:
335         self.do_switches()
336      elif string.find(command, "D",0) == 0:
337         self.do_display(command[1:])
338      self.do_prompt()
339         
340
341 # we start the app like this...
342 app=appgui()
343 gtk.mainloop()
344
345
346 # notes
347 # http://www.async.com.br/faq/pygtk/index.py?req=show&file=faq20.011.htp

UCC git Repository :: git.ucc.asn.au