This URL has Read-Only access.

Statistics
| Branch: | Revision:

root / telechachagui.py @ master

History | View | Annotate | Download (26.8 kB)

1
#!/usr/bin/env python
2

    
3

    
4
### GENERAL NOTES  ###
5
"""
6
- voir si il faut gerer une demande de connexion alors que c'est deja connecte
7
- voir si le bouton "cancel" est necesaire dans la fenetre "contacting" :
8
        - si oui il faudra trouver un moyen de faire la connection sans bloquer l'interface
9
        (thread, idle gtk ou io_watch?)
10
- en prod regler test a 0
11
- bug pour setter le bouton par defaut quand on change de tab. Il faut que le tab est le focus pour que ca marche. Pourtant le "print" apparait ???
12
"""
13

    
14

    
15
### CONSTANTS ###
16

    
17
_TEST = 0
18
__version__ = 1.0
19

    
20

    
21
### MODULES IMPORTS  ###
22

    
23
import sys
24
import random
25
import os, signal
26
import time
27
import socket
28
import smtplib
29
import popen2
30
import re
31

    
32

    
33
try:
34
        import pygtk
35
        pygtk.require("2.0")
36
except:
37
        pass
38
try:
39
        import gtk
40
        import gtk.glade
41
        import gobject
42
except:
43
        sys.exit(1)
44

    
45

    
46

    
47
### MULTILINGUAL SUPPORT ###
48
APP = "telechachagui"
49
DIR = "locale"
50

    
51
import gettext
52

    
53
_ = gettext.gettext
54

    
55
gettext.bindtextdomain(APP, DIR)
56
gettext.textdomain(APP)
57
gtk.glade.bindtextdomain(APP, DIR)
58
gtk.glade.textdomain(APP)
59

    
60

    
61

    
62

    
63
### MAIN MEDIATOR(CONTROLLER)/COLLEAGUE CLASSES ###
64

    
65
class Mediator:
66
        def __init__(self):
67
                self.config = Config()
68

    
69
                self.ad_book = AddressBook()
70
                
71
                self.dv_proc = DVProcess(self)
72
                
73
                if len(sys.argv) > 1 and (sys.argv[1] == "-k" or sys.argv[1] == "--kiosk"):
74
                        kiosk = 1
75
                else:
76
                        kiosk = 0
77

    
78
                self.gui = GuiClass(self, kiosk)
79

    
80
                self.server = Server(self)
81
                self.server.start_listening()
82
                
83
                gtk.main()
84

    
85
        def colleague_changed(self, colleague, event, event_args):
86
                if hasattr(self, event):
87
                        if event_args:
88
                                eval("self." + event)(colleague, event_args)
89
                        else:
90
                                eval("self." + event)(colleague)
91

    
92

    
93
        ### General Methods ###
94

    
95
        def set_contact_dialog(self, text, gui=None):
96
                if not gui:
97
                        gui = self.gui
98
                gui.contact_problem_label.set_label(text)
99
                answ = gui.contact_dialog.run()
100
                gui.contact_dialog.hide()
101
                if answ == gtk.RESPONSE_OK:
102
                        return 1
103
                else:
104
                        return 0
105

    
106
        def set_confirm_dialog(self, text, gui=None):
107
                if not gui:
108
                        gui = self.gui
109
                gui.confirm_label.set_label(text)
110
                answ = gui.dialog.run()
111
                gui.dialog.hide()
112
                if answ == gtk.RESPONSE_OK:
113
                        return 1
114
                else:
115
                        return 0
116

    
117
        def hide_contacting_window(self, msg="", err=""):
118
                self.gui.contacting_window.hide()
119
                text = None
120
                if msg == "err":
121
                        text = _("<b><big>Contact unreacheable.</big></b>\n\nCould not connect to the IP address of this contact.")
122
                elif msg == "timeout":
123
                        text = _("<b><big>Connection timeout.</big></b>\n\nCould not connect to the port of this contact.")
124
                elif msg == "answTimeout":
125
                        text = _("<b><big>Contact answer timeout.</big></b>\n\nThe contact did not answer in an reasonable delay.")
126
                elif msg == "send":
127
                        text = _("<b><big>Problem sending command.</big></b>\n\nError: %s") % err
128
                elif msg == "refuse":
129
                        text = _("<b><big>Connection refuse.</big></b>\n\nThe contact refuse the connection.")
130
                elif msg == "badAnsw":
131
                        text = _("<b><big>Invalid answer.</big></b>\n\nThe answer was not valid.")
132
                if text:
133
                        if self.set_contact_dialog(text):
134
                                pass
135

    
136

    
137
        ### Callbacks ###
138

    
139
        def check_ext_program(self, gui):
140
                global __version__, _TEST
141
                if not _TEST:
142
                        # verify xdvshow and dvsend and get versions
143
                        try:
144
                                w, r, err = os.popen3(self.config.dvsend + ' -v')
145
                                err_str = err.read()
146
                                if err_str:
147
                                        text = _("<b><big>Could not start dvsend?</big></b>\n\nError: %s. Quitting.") % err_str
148
                                        if self.set_contact_dialog(text, gui):
149
                                                pass
150
                                        sys.exit()
151
                                else:
152
                                        match = re.search(r'version ([^ \n]+)', r.readline(), re.I)
153
                                        if match:
154
                                                self.dvsend_version = match.group(1)
155
                                        else:
156
                                                self.dvsend_version = "?"
157
                                w.close()
158
                                r.close()
159
                                err.close()
160
                        except:
161
                                text = _("<b><big>Could not start dvsend?</big></b>\n\nCould not start dvsend. Quitting.")
162
                                if self.set_contact_dialog(text, gui):
163
                                        pass
164
                                sys.exit()
165

    
166
                        try:
167
                                w, r, err = os.popen3(self.config.xdvshow + ' -v')
168
                                err_str = err.read()
169

    
170
                                ### a remettre quand xdvshow ne retournera plus d'erreur par defaut ###
171
                                #~ if err_str:
172
                                        #~ text = (_("<b><big>Could not start xdvshow?</big></b>\n\nError: %(err_str). Quitting."), err_str)
173
                                        #~ if self.set_contact_dialog(text, gui):
174
                                                #~ pass
175
                                        #~ sys.exit()
176
                                #~ else:
177
                                match = re.search(r'version ([^ \n]+)', r.readline(), re.I)
178
                                if match:
179
                                        self.xdvshow_version = match.group(1)
180
                                else:
181
                                        self.xdvshow_version = "?"
182

    
183
                                w.close()
184
                                r.close()
185
                                err.close()
186
                        except:
187
                                text = _("<b><big>Could not start xdvshow?</big></b>\n\nCould not start xdvshow. Quitting.")
188
                                if self.set_contact_dialog(text, gui):
189
                                        pass
190
                                sys.exit()
191

    
192
                        else:
193
                                text = _("<b><big>teleCHACHA</big></b>\nVersion: ")
194
                                text += str(__version__)
195
                                text += _("\ndvsend: ") + self.dvsend_version
196
                                text += _("\nxdvshow: ") + self.xdvshow_version
197
                                text += _("\nCopyright: SAT")
198
                                text += _("\nAuthors: Etienne Desautels")
199

    
200
                if _TEST:
201
                        self.dvsend_version = '1.23'
202
                        self.xdvshow_version = '1.21'
203

    
204
                        text = _("<b><big>teleCHACHA</big></b>\nVersion: ")
205
                        text += str(__version__)
206
                        text += _("\ndvsend: ") + self.dvsend_version
207
                        text += _("\nxdvshow: ") + self.xdvshow_version
208
                        text += _("\nCopyright: SAT")
209
                        text += _("\nAuthors: Etienne Desautels")
210
                                                
211
                gui.info_label.set_label(text)
212

    
213

    
214
        def on_main_window_destroy(self, colleague, (widget)):
215
                self.server.close()
216
                self.ad_book.write()
217
                self.dv_proc.stop()
218
                gtk.main_quit()
219

    
220

    
221
        def on_main_tabs_switch_page(self, gui, (widget, page, page_num)):
222
                tab = widget.get_nth_page(page_num).name
223
                if tab == "localPan":
224
                        gui.widgets.get_widget("netConfSetBut").grab_default()
225
                if tab == "contactPan":
226
                        gui.widgets.get_widget("contactJoinBut").grab_default()
227

    
228
        def init_bandwidth(self, gui):
229
                base = 30
230
                num = 2        # number of choice
231
                selection = int(round((self.config.bandwidth - 1) * num / base))
232
                if selection < 0:
233
                        selection = 0
234
                elif selection > base:
235
                        selection = base
236
                gui.net_conf_bw_combo.set_active(selection)
237

    
238
        def on_net_conf_bw_combo_changed(self, gui, (widget)):
239
                base = 30
240
                num = 2        # number of choice
241
                step = base / num
242
                selection = gui.net_conf_bw_combo.get_active()
243
                self.config.bandwidth = (selection + 1) * step
244
                self.config._write()
245

    
246
        def init_negotiation_port(self, gui):
247
                gui.negotiation_port_entry.set_text(str(self.config.negotiationport))
248

    
249
        def on_net_conf_port_entry_changed2(self, gui, (widget)):
250
                port = gui.negotiation_port_entry.get_text()
251
                if not port.isdigit():
252
                        gui.widgets.get_widget("mainTabs").set_current_page(1)
253
                        self.init_negotiation_port(gui)
254
                        text = _("<b><big>The port number is not valid</big></b>\n\nEnter a valid port number in the range of 1-999999")
255
                        if self.set_contact_dialog(text):
256
                                gui.negotiation_port_entry.grab_focus()
257
                                return False
258
                else:
259
                        self.config.negotiationport = int(port)
260
                        self.config._write()
261
                        self.server.close()
262
                        self.server = Server(self)
263
                        self.server.start_listening()
264
                
265

    
266
        def init_ad_book_list(self, gui):
267
                ad_book = self.ad_book
268
                ad_book.contact = None
269
                ad_book.new_contact = 0
270
                
271
                if len(ad_book.list) > 0:
272
                        for contact in ad_book.list:
273
                                gui.contact_tree.append(        ["<b>" + contact["name"]
274
                                                                                        + "</b>\n  IP: "
275
                                                                                        + contact["address"] + "\n  Port: "
276
                                                                                        + str(contact["port"])]        )
277
                        gui.selection.select_path(ad_book.selected)
278
                else:
279
                        gui.contact_edit_but.set_sensitive(False)
280
                        gui.remove_contact.set_sensitive(False)
281
                        gui.contact_join_but.set_sensitive(False)
282

    
283
        def on_contact_list_changed(self, gui, (widget, data)):
284
                list, gui.row = widget.get_selected()
285
                if gui.row:
286
                        gui.contact_edit_but.set_sensitive(True)
287
                        gui.remove_contact.set_sensitive(True)
288
                        gui.contact_join_but.set_sensitive(True)
289

    
290
                        self.num = list.get_path(gui.row)[0]
291
                        self.ad_book.contact = self.ad_book.list[self.num]
292
                        self.ad_book.selected = self.num
293
                else:
294
                        gui.contact_edit_but.set_sensitive(False)
295
                        gui.remove_contact.set_sensitive(False)
296
                        gui.contact_join_but.set_sensitive(False)
297

    
298
                        self.ad_book.contact = None
299

    
300
        def on_add_contact_clicked(self, gui, (widget)):
301
                self.ad_book.new_contact = 1
302
                gui.contact_name_entry.set_text("")
303
                gui.contact_ip_entry.set_text("")
304
                gui.contact_port_entry.set_text("")
305
                gui.edit_contact_window.show()
306

    
307
        def on_remove_contact_clicked(self, gui, (widget)):
308
                text = _("<b><big>Delete this contact from the list?</big></b>\n\nAre you sure you want to delete this contact from the list?")
309
                if self.set_confirm_dialog(text):
310
                        del self.ad_book.list[self.num]
311
                        gui.contact_tree.remove(gui.row)
312
                        self.ad_book.write()
313
                        num = self.num - 1
314
                        if num < 0:
315
                                num = 0
316
                        gui.selection.select_path(num)
317

    
318
        def on_contact_edit_but_clicked(self, gui, (widget)):
319
                gui.contact_name_entry.set_text(self.ad_book.contact["name"])
320
                gui.contact_ip_entry.set_text(self.ad_book.contact["address"])
321
                gui.contact_port_entry.set_text(str(self.ad_book.contact["port"]))
322
                gui.edit_contact_window.show()
323

    
324
        def on_edit_contact_window_delete_event(self, gui, (widget, event)):
325
                widget.hide()
326

    
327
        def on_edit_contact_cancel_but_clicked(self, gui, (widget)):
328
                gui.edit_contact_window.hide()
329

    
330
        def on_edit_contact_save_but_clicked(self, gui, (widget)):
331
                ad_book = self.ad_book
332
                #Validate the port number
333
                port = gui.contact_port_entry.get_text()
334
                if port == "":
335
                        port = str(self.config.dvsendport)        #set port to default
336
                elif (not port.isdigit()) or (int(port) not in range(1,10000)):
337
                        text = _("<b><big>The port number is not valid</big></b>\n\nEnter a valid port number in the range of 1000-99999")
338
                        if self.set_contact_dialog(text):
339
                                return
340

    
341
                #Validate the address
342
                addr = gui.contact_ip_entry.get_text()
343
                if len(addr) < 7:
344
                        text = _("<b><big>The address is not valid</big></b>\n\nEnter a valid address\nExample: 168.123.45.32 or tot.sat.qc.ca")
345
                        if self.set_contact_dialog(text):
346
                                return
347

    
348
                if ad_book.new_contact:
349
                        gui.contact_tree.append(        ["<b>" + gui.contact_name_entry.get_text()
350
                                                                                + "</b>\n  IP: " + addr
351
                                                                                + "\n  Port: " + port]        )
352
                        ad_book.list.append({})
353
                        gui.selection.select_path(len(ad_book.list) - 1)
354
                        ad_book.contact = ad_book.list[len(ad_book.list) - 1]
355
                        ad_book.new_contact = 0
356
                else:
357
                        gui.contact_tree.set_value(gui.row, 0, "<b>" + gui.contact_name_entry.get_text() + "</b>\n  IP: " + addr + "\n  Port: " + port)
358
                ad_book.contact["name"] = gui.contact_name_entry.get_text()
359
                ad_book.contact["address"] = addr
360
                ad_book.contact["port"] = int(port)
361
                ad_book.write()
362
                gui.edit_contact_window.hide()
363

    
364

    
365
        def on_net_conf_set_but_clicked(self, gui, (widget)):
366
                os.system('gksudo "network-admin"')
367

    
368
        def on_sys_shutdown_but_clicked(self, gui, (widget)):
369
                text = _("<b><big>Shutdown the computer?</big></b>\n\nAre you sure you want to shutdown the computer now?")
370
                if self.set_confirm_dialog(text):
371
                        os.system('gksudo "shutdown -h now"')
372

    
373
        def on_sys_reboot_but_clicked(self, gui, (widget)):
374
                text = _("<b><big>Reboot the computer?</big></b>\n\nAre you sure you want to reboot the computer now?")
375
                if self.set_confirm_dialog(text):
376
                        os.system('gksudo "shutdown -r now"')
377

    
378
        def on_maint_upd_but_clicked(self, gui, (widget)):
379
                os.system('gksudo "update-manager"')
380

    
381
        def on_maint_send_but_clicked(self, gui, (widget)):
382
                text = _("<b><big>Send the settings?</big></b>\n\nAre you sure you want to send your computer settings to the administrator of teleCHACHA?")
383
                if self.set_confirm_dialog(text):
384
                        msg = "--- dvsend ---\n" + self.dvsend_version + "\n\n"
385
                        msg += "--- xdvshow ---\n" + self.xdvshow_version + "\n\n"
386
                        msg += "--- uname -a ---\n"
387
                        try:
388
                                w, r, err = os.popen3('uname -a')
389
                                msg += r.read() + "\n"
390
                                errRead = err.read()
391
                                if errRead:
392
                                        msg += errRead + "\n"
393
                                w.close()
394
                                r.close()
395
                                err.close()
396
                        except:
397
                                msg += "Error executing 'uname -a'\n\n"
398
                        msg += "--- lsmod ---\n"
399
                        try:
400
                                w, r, err = os.popen3('lsmod')
401
                                msg += r.read()
402
                                errRead = err.read()
403
                                if errRead:
404
                                        msg += "\n" + errRead
405
                                w.close()
406
                                r.close()
407
                                err.close()
408
                        except:
409
                                msg += "Error executing 'lsmod'"
410

    
411
                        fromaddr = "telechacha@sat.qc.ca"
412
                        toaddrs  = self.config.emailinfo
413
                        toaddrs = toaddrs.split(', ')
414
                        server = smtplib.SMTP(self.config.smtpserver)
415
                        server.set_debuglevel(0)
416
                        try:
417
                                server.sendmail(fromaddr, toaddrs, msg)
418
                        except:
419
                                text = _("<b><big>Could not send info.</big></b>\n\nCheck your internet connection.")
420
                                if self.set_contact_dialog(text):
421
                                        pass
422
                        server.quit()
423

    
424
        def on_client_join_but_clicked(self, gui, (widget)):
425
                gui.contacting_window.show()
426
                msg = repr({"command":"ask", "port":self.ad_book.contact["port"], "bandwidth":self.config.bandwidth})
427
                client = Client(self)        ###############
428
                gobject.idle_add(client.connect, self.ad_book.contact["address"], msg)
429
        
430

    
431
        def on_server_rcv_command(self, server, (msg, addr, conn)):
432
                if msg and "command" in msg:
433
                        cmd = msg["command"]
434
                        if cmd == "ask":
435
                                self.rcv_watch = gobject.timeout_add(5000, self.server_answer_timeout, addr[0])
436
                                self.gui.contact_request_label.set_label("<b><big>" + addr[0] + " is contacting you.</big></b>\n\nDo you accept the connection?")
437
                                answ = self.gui.contact_request_dialog.run()
438
                                gobject.source_remove(self.rcv_watch)
439
                                self.gui.contact_request_dialog.hide()
440
                                if answ == gtk.RESPONSE_OK:
441
                                        if "bandwidth" in msg and self.config.bandwidth > msg["bandwidth"]:
442
                                                bandwidth = msg["bandwidth"]
443
                                        else:
444
                                                bandwidth = self.config.bandwidth
445
                                        conn.sendall(repr({"answer":"accept", "bandwidth": bandwidth}))
446
                                        conn.close()
447
                                        self.dv_proc.start(addr[0], bandwidth)
448
                                else:
449
                                        conn.sendall(repr({"answer":"refuse"}))
450
                                        conn.close()
451
                        elif cmd == "stop":
452
                                self.dv_proc.stop()
453
                                conn.sendall(repr({"answer":"stopped"}))
454
                                conn.close()
455
                        else:
456
                                conn.close()
457
                else:
458
                        conn.close()
459

    
460
        def server_answer_timeout(self, addr):
461
                self.gui.contact_request_dialog.response(gtk.RESPONSE_NONE)
462
                self.gui.contact_request_dialog.hide()
463
                text = _("<b><big>%s was contacting you.</big></b>\n\nBut you did not answer in reasonable delay.") % addr
464
                if self.set_contact_dialog(text):
465
                        pass
466
                return False
467

    
468

    
469
        def on_client_socket_timeout(self, client):
470
                #~ if self.widgets:        ############
471
                self.hide_contacting_window("timeout")
472
        
473
        def on_client_socket_error(self, client, (err, msg)):
474
                #~ if self.widgets:        ############
475
                self.hide_contacting_window(msg)
476
                print err
477

    
478
        def on_client_add_timeout(self, client):
479
                #~ if self.gui.contacting_window.get_property('visible'):
480
                self.answ_watch = gobject.timeout_add(5000, self.client_answer_timeout, client)
481
                #~ return False
482

    
483
        def on_client_rcv_command(self, client, (msg)):
484
                if(self.answ_watch):
485
                        gobject.source_remove(self.answ_watch)
486
                if msg and "answer" in msg:
487
                        answ = msg["answer"]
488
                        if answ == "accept":
489
                                self.hide_contacting_window("accept")
490
                                if "bandwidth" in msg:
491
                                        bandwidth = msg["bandwidth"]
492
                                else:
493
                                        bandwidth = self.config.bandwidth
494
                                self.dv_proc.start(client.host, bandwidth)
495
                        elif answ == "refuse":
496
                                self.hide_contacting_window("refuse")
497
                        elif answ == "stopped":
498
                                self.dv_proc.stop()
499
                        else:
500
                                self.hide_contacting_window("badAnsw")
501

    
502
        def client_answer_timeout(self, client):
503
                if (client.io_watch):
504
                        gobject.source_remove(client.io_watch)
505
                if self.gui.contacting_window.get_property('visible'):
506
                        self.hide_contacting_window("answTimeout")
507
                return False
508
        
509
        
510
        def on_start_dv(self, colleague):
511
                self.gui.contact_join_but.set_sensitive(False)
512

    
513
        def on_stop_dv(self, colleague):
514
                self.gui.contact_join_but.set_sensitive(True)
515

    
516
        def watch_xdvshow(self, colleague, (child, condition)):
517
                msg = repr({"command":"stop"})
518
                client = Client(self)
519
                client.connect(self.ad_book.contact["address"], msg)
520
                #~ client.close()
521
                
522

    
523

    
524
class Colleague:
525
        def __init__(self, med):
526
                self.med = med
527

    
528
        def _changed(self, colleague, event_args=None, event=None):
529
                if not event:
530
                        event = sys._getframe(1).f_code.co_name
531
                self.med.colleague_changed(colleague, event, event_args)
532

    
533

    
534

    
535
### READING AND WRITING CONFIGURATION FILE ###
536

    
537
class Config:
538
        # Default values
539
        dvsendport = 8000
540
        negotiationport = 17446
541
        dvsend = "dvsend"
542
        xdvshow = "xdvshow"
543
        smtpserver = "smtp.sat.qc.ca"
544
        emailinfo = "telechacha@sat.qc.ca"
545
        audiolib = "oss"
546
        bandwidth = 30
547

    
548

    
549
        def __init__(self):
550
                config_file = 'telechacha.cfg'
551
                if os.path.isfile('/etc/' + config_file):
552
                        config_path = '/etc/'
553
                else:
554
                        config_path = os.environ['HOME'] + '/.telechacha/'
555
                self.config_path = config_path + config_file
556

    
557
                if os.path.isfile(self.config_path):
558
                        self._read()
559
                else:
560
                        if not os.path.isdir(config_path):
561
                                os.mkdir(config_path)
562
                        self._write()
563

    
564
        def _write(self):
565
                global __version__
566
                config_str = _("# Configuration written by %(app)s %(version)s\n") % {'app': sys.argv[0], 'version': __version__}
567
                for c in dir(self.__class__):
568
                        if c[0] != '_' and hasattr(self, c):
569
                                inst_attr = getattr(self, c)
570
                                if inst_attr == getattr(Config, c):
571
                                        comment = "# "
572
                                else:
573
                                        comment = ""
574
                                config_str += "\n" + comment + c + "=" + str(inst_attr)
575
                config_file = file(self.config_path, "w")
576
                config_file.write(config_str)
577
                config_file.close()
578

    
579
        def _read(self):
580
                config_file  = file(self.config_path, "r")
581
                for line in config_file:
582
                        line = line.strip()
583
                        if line and line[0] != "#" and len(line) > 2:
584
                                try:
585
                                        item = line.split("=")
586
                                        item[0] = item[0].strip()
587
                                        item[1] = item[1].strip()
588
                                        if item[1].isdigit():
589
                                                item[1] = int(item[1])
590
                                        setattr(self, item[0], item[1])
591
                                except:
592
                                        pass
593
                config_file.close()
594

    
595

    
596
### READING & WRITING ADDRESS BOOK FILE ###
597

    
598
class AddressBook:
599
        def __init__(self):
600
                self.list = []
601
                self.selected = 0
602
                self.ad_book_name = os.environ['HOME'] + '/.telechacha/telechacha.adb'
603
                self.read()
604

    
605
        def read(self):
606
                if os.path.isfile(self.ad_book_name):
607
                        self.list = []
608
                        ad_book_file = file(self.ad_book_name, "r")
609
                        for line in ad_book_file:
610
                                if line[:4] == "sel:":
611
                                        self.selected = int(line[4:].strip())
612
                                else:
613
                                        try:
614
                                                self.list.append(eval(line))
615
                                        except:
616
                                                pass
617
                        ad_book_file.close()
618

    
619
        def write(self):
620
                if ((os.path.isfile(self.ad_book_name)) or (len(self.list) > 0)):
621
                        try:
622
                                ad_book_file = file(self.ad_book_name, "w")
623
                                for contact in self.list:
624
                                        ad_book_file.write(repr(contact) + "\n")
625
                                if self.selected:
626
                                        ad_book_file.write("sel:" + str(self.selected) + "\n")
627
                                ad_book_file.close()
628
                        except:
629
                                print _("Cannot write Address Book file")
630

    
631

    
632

    
633

    
634

    
635
### GTK GUI ###
636

    
637
class GuiClass(Colleague):
638
        def __init__(self, med, kiosk):
639
                global _TEST, __version__
640
                
641
                Colleague.__init__(self, med)
642

    
643
                # Set the Glade file
644
                glade_file = 'telechachagui.glade'
645
                if os.path.isfile(glade_file):
646
                        glade_path = glade_file
647
                elif os.path.isfile('/usr/share/telechachagui/' + glade_file):
648
                        glade_path = '/usr/share/telechachagui/' + glade_file
649
                else:
650
                        text = _("<b><big>Could not find the Glade file?</big></b>\n\nBe sure the file %s is in /usr/share/telechachagui/. Quitting.") % glade_file
651
                        print text
652
                        sys.exit()
653

    
654

    
655
                self.widgets = gtk.glade.XML(glade_path, domain=APP)
656
                
657
                # connects callbacks to widgets automatically
658
                cb = {}
659
                for n in dir(self.__class__):
660
                        if n[0] != '_' and hasattr(self, n):
661
                                cb[n] = getattr(self, n)
662

    
663
                self.widgets.signal_autoconnect(cb)
664

    
665
                # get all the widgets that we use
666
                self.main_window = self.widgets.get_widget("mainWindow")
667
                self.dialog = self.widgets.get_widget("normalDialog")
668
                self.dialog.set_transient_for(self.main_window)
669
                self.confirm_label = self.widgets.get_widget("confirmLabel")
670
#                self.client_preview = self.widgets.get_widget("clientPreviewWindow")
671
                self.contacting_window = self.widgets.get_widget("contactingWindow")
672
                self.contact_dialog = self.widgets.get_widget("contactDialog")
673
                self.contact_dialog.set_transient_for(self.main_window)
674
                self.contact_problem_label = self.widgets.get_widget("contactProblemLabel")
675
                self.contact_request_dialog = self.widgets.get_widget("contactRequestDialog")
676
                self.contact_request_dialog.set_transient_for(self.main_window)
677
                self.contact_request_label = self.widgets.get_widget("contactRequestLabel")
678
                self.edit_contact_window = self.widgets.get_widget("editContactWindow")
679
                self.edit_contact_window.set_transient_for(self.main_window)
680
                self.contact_name_entry = self.widgets.get_widget("contactNameEntry")
681
                self.contact_ip_entry = self.widgets.get_widget("contactIPEntry")
682
                self.contact_port_entry = self.widgets.get_widget("contactPortEntry")
683
                self.contact_edit_but = self.widgets.get_widget("contactEditBut")
684
                self.remove_contact = self.widgets.get_widget("removeContact")
685
                self.contact_join_but = self.widgets.get_widget("contactJoinBut")
686
                self.info_label = self.widgets.get_widget("infoLabel")
687
                self.contact_list = self.widgets.get_widget("contactList")
688
                self.negotiation_port_entry = self.widgets.get_widget("netConfPortEntry")
689

    
690
                self.net_conf_bw_combo = self.widgets.get_widget("netConfBWCombo")
691

    
692

    
693
                # verify xdvshow and dvsend
694
                self._changed(self, event="check_ext_program")
695
                
696
                # adjust the bandwidth combobox iniline with the config
697
                self._changed(self, event="init_bandwidth")
698
                
699
                # switch to Kiosk mode if asked
700
                if kiosk:
701
                        self.main_window.set_decorated(False)
702
                        self.widgets.get_widget("sysBox").show()
703

    
704
                # Build the contact list view
705
                self.selection = self.contact_list.get_selection()
706
                self.selection.connect("changed", self.on_contact_list_changed, None)
707

    
708
                self.contact_tree = gtk.ListStore(str)
709
                self.contact_list.set_model(self.contact_tree)
710
                column = gtk.TreeViewColumn(_("Contacts"), gtk.CellRendererText(), markup=0)
711
                self.contact_list.append_column(column)
712
                
713
                self._changed(self, event="init_ad_book_list")
714
                
715
                self._changed(self, event="init_negotiation_port")
716
                
717
                self.main_window.show()
718
                
719
                
720
        ### GUI Callbacks ###
721
        
722
        def on_main_window_destroy(self, *args):
723
                self._changed(self, args)
724

    
725

    
726
        def on_main_tabs_switch_page(self, *args):
727
                self._changed(self, args)
728

    
729

    
730
        def on_contact_list_changed(self, *args):
731
                self._changed(self, args)
732

    
733
        def on_contact_list_row_activated(self, *args):
734
                self._changed(self, args, event="on_contact_edit_but_clicked")
735

    
736
        def on_add_contact_clicked(self, *args):
737
                self._changed(self, args)
738

    
739
        def on_remove_contact_clicked(self, *args):
740
                self._changed(self, args)
741

    
742
        def on_contact_edit_but_clicked(self, *args):
743
                self._changed(self, args)
744

    
745
        def on_edit_contact_window_delete_event(self, *args):
746
                self._changed(self, args)
747
                return True
748

    
749
        def on_edit_contact_cancel_but_clicked(self, *args):
750
                self._changed(self, args)
751

    
752
        def on_edit_contact_save_but_clicked(self, *args):
753
                self._changed(self, args)
754

    
755

    
756
        def on_net_conf_set_but_clicked(self, *args):
757
                self._changed(self, args)
758

    
759
        def on_sys_shutdown_but_clicked(self, *args):
760
                self._changed(self, args)
761

    
762
        def on_sys_reboot_but_clicked(self, *args):
763
                self._changed(self, args)
764

    
765
        def on_maint_upd_but_clicked(self, *args):
766
                self._changed(self, args)
767

    
768
        def on_maint_send_but_clicked(self, *args):
769
                self._changed(self, args)
770

    
771

    
772
        def on_client_join_but_clicked(self, *args):
773
                self._changed(self, args)
774

    
775

    
776
        def on_net_conf_bw_combo_changed(self, *args):
777
                self._changed(self, args)
778

    
779
        def on_net_conf_port_entry_changed(self, *args):
780
                gobject.timeout_add(0, self.on_net_conf_port_entry_changed2, args)
781
                return False
782

    
783
        def on_net_conf_port_entry_changed2(self, *args):
784
                self._changed(self, args)
785

    
786
### DV... PROCESS ###
787

    
788
class DVProcess(Colleague):
789
        def __init__(self, med):
790
                Colleague.__init__(self, med)
791
                self.config = med.config
792
                self.video_port = self.config.dvsendport
793
                self.audio_port = self.video_port + 2
794
                
795
        def start(self, host, bandwidth):
796
        
797
                self._changed(self, event="on_start_dv")
798
                
799
                base = 30
800
                divider = base / bandwidth
801
                
802
                self.dvsend_pid = os.spawnlp(        os.P_NOWAIT,
803
                                                                                self.config.dvsend,
804
                                                                                self.config.dvsend,
805
                                                                                '-h', host,
806
                                                                                '-P', str(self.video_port),
807
                                                                                '-A', str(self.audio_port)        )
808
                                                                                #~ '-F', str(divider)        )
809

    
810
                self.xdvshow_child = popen2.Popen3(        self.config.xdvshow
811
                                                                                        + ' -F -a ' + self.config.audiolib
812
                                                                                        +' -P ' + str(self.video_port)
813
                                                                                        + ' -A ' + str(self.audio_port)        )
814

    
815
                self.watch = gobject.io_add_watch(        self.xdvshow_child.fromchild,
816
                                                                                        gobject.IO_HUP,
817
                                                                                        self.watch_xdvshow        )
818

    
819
        def watch_xdvshow(self, *args):
820
                self._changed(self, args)
821
                self.timeout = gobject.timeout_add(5000, self.stop)
822
                return False
823

    
824
        def stop(self):
825
                if hasattr(self, "watch"):
826
                        gobject.source_remove(self.watch)
827
                if hasattr(self, "timeout"):
828
                        gobject.source_remove(self.timeout)
829
                        
830
                try:
831
                        os.kill(self.xdvshow_child.pid, signal.SIGTERM)
832
                        os.wait()
833
                except:
834
                        pass
835
                try:
836
                        os.kill(self.dvsend_pid, signal.SIGTERM)
837
                        os.wait()
838
                except:
839
                        pass
840
                        
841
                self._changed(self, event="on_stop_dv")
842

    
843

    
844

    
845

    
846

    
847
### NETWORK ###
848

    
849
class Network(Colleague):
850
        def __init__(self, med):
851
                Colleague.__init__(self, med)
852
                self.config = med.config
853
                self.buf_size = 1024
854
                self.port = self.config.negotiationport
855

    
856

    
857
        def validate(self, msg):
858
                tmp_msg = msg.strip()
859
                msg = None
860
                if tmp_msg[0] == "{" and tmp_msg[-1] == "}" and tmp_msg.find("{",1,-2) == -1 and tmp_msg.find("}",1,-2) == -1:
861
                        try:
862
                                tmp_msg = eval(tmp_msg)
863
                                if type(tmp_msg) is dict:
864
                                        msg = tmp_msg
865
                        except:
866
                                pass
867
                return msg
868

    
869
        def recv(self, conn):
870
                data = conn.recv(self.buf_size)
871
                buffer = data
872
                while len(data) == self.buf_size: # maybe we should recall handle_data on io_watch
873
                        data = conn.recv(self.buf_size)
874
                        buffer += data
875
                return buffer
876

    
877
        def close(self):
878
                self.sock.close()
879

    
880

    
881
class Server(Network):
882
        def __init__(self, med):
883
                global _TEST
884
                Network.__init__(self, med)
885
                self.host = ''
886

    
887
                if _TEST:
888
                        self.port = int(sys.argv[1])
889
                        self.host = socket.gethostname()
890

    
891
        def start_listening(self):
892
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
893
                sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
894
                sock.bind((self.host, self.port))
895
                sock.listen(1)
896
                gobject.io_add_watch(sock, gobject.IO_IN, self.handle_data)
897
                self.sock = sock
898

    
899
        def handle_data(self, source, condition):
900
                conn, addr = source.accept()
901
                buffer = self.recv(conn)
902
                msg = self.validate(buffer)
903

    
904
                self._changed(self, (msg, addr, conn), event="on_server_rcv_command")
905
                return True
906
                
907

    
908

    
909
class Client(Network):
910
        def __init__(self, med):
911
                global _TEST
912
                Network.__init__(self, med)
913
                self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
914
                self.sock.settimeout(10)
915

    
916
                if _TEST:
917
                        self.port = int(sys.argv[2])
918

    
919
        def connect(self, host, msg):
920
                self.host = host
921
                try:
922
                        self.sock.connect((host, self.port))
923
                except socket.timeout, err:
924
                        self._changed(self, event="on_client_socket_timeout")
925
                except socket.error, err:
926
                        self._changed(self, (err, "err"), event="on_client_socket_error")
927
                else:
928
                        if self.send(msg):
929
                                #~ if self.widgets:        ###############
930
                                self.io_watch = gobject.io_add_watch(self.sock, gobject.IO_IN, self.handle_data)
931
                return False
932

    
933
        def send(self, msg):
934
                if not len(msg)%self.buf_size:
935
                        msg += " "
936
                try:
937
                        self.sock.sendall(msg)
938
                        self._changed(self, event="on_client_add_timeout")
939
                        return True
940
                except socket.error, err:
941
                        self._changed(self, err, event="on_client_add_timeout")
942
                        self._changed(self, "send", err, event="on_client_socket_error")
943
                        return False
944

    
945
        def handle_data(self, source, condition):
946
                buffer = self.recv(source)
947
                source.close()
948
                msg = self.validate(buffer)
949
                self._changed(self, msg, event="on_client_rcv_command")
950
                return False
951

    
952

    
953

    
954
if __name__ == '__main__':
955
        main = Mediator()