|
@@ -17,6 +17,33 @@
|
17
|
17
|
# You should have received a copy of the GNU General Public License
|
18
|
18
|
# along with pyMapTraceroute. If not, see <http://www.gnu.org/licenses/>.
|
19
|
19
|
#
|
|
20
|
+control_summary = [
|
|
21
|
+"+----------------------+----------------------------------+",
|
|
22
|
+"| Controls summary |",
|
|
23
|
+"+----------------------+----------------------------------+",
|
|
24
|
+"+----------------------+----------------------------------+",
|
|
25
|
+"| ^h, ? | display this help |",
|
|
26
|
+"+----------------------+----------------------------------+",
|
|
27
|
+"| esc, ^q | exit the programm or this help |",
|
|
28
|
+"+----------------------+----------------------------------+",
|
|
29
|
+"+----------------------+----------------------------------+",
|
|
30
|
+"| [a-zA-Z0-9\.] | Host input |",
|
|
31
|
+"+----------------------+----------------------------------+",
|
|
32
|
+"| mid-mouse btn | paste clipboard into host input |",
|
|
33
|
+"+----------------------+----------------------------------+",
|
|
34
|
+"| enter | validate host input and |",
|
|
35
|
+"| | run traceroute |",
|
|
36
|
+"+----------------------+----------------------------------+",
|
|
37
|
+"| ^c | clear host input |",
|
|
38
|
+"+----------------------+----------------------------------+",
|
|
39
|
+"+----------------------+----------------------------------+",
|
|
40
|
+"| mouse scroll, +, - : zoom in/out |",
|
|
41
|
+"+----------------------+----------------------------------+",
|
|
42
|
+"| arrow keys : move on the map |",
|
|
43
|
+"+----------------------+----------------------------------+",
|
|
44
|
+"| left mouse btn press : select hops on the map |",
|
|
45
|
+"+----------------------+----------------------------------+"
|
|
46
|
+]
|
20
|
47
|
|
21
|
48
|
import websocket
|
22
|
49
|
import random
|
|
@@ -41,7 +68,7 @@ class Vtracert:
|
41
|
68
|
# @param fonts Override default font type and size its a dict of tuple (fontType, fontSize), valid keys are : prompt, status
|
42
|
69
|
# @param promptText The prompt when reading the host to traceroute
|
43
|
70
|
# @param defaultInput Default host to traceroute
|
44
|
|
- def __init__(self, mapdatfile, width = 1024, height = 768, cols = dict(), fonts = dict(), promptText = "Type the ip or hostname to traceroute : %s_", defaultInput = "gnu.org"):
|
|
71
|
+ def __init__(self, mapdatfile, width = 1024, height = 768, cols = dict(), fonts = dict(), promptText = "Enter an ip or an hostname and press enter to traceroute : %s_", defaultInput = "gnu.org"):
|
45
|
72
|
|
46
|
73
|
pygame.init() #Pygame init
|
47
|
74
|
|
|
@@ -51,6 +78,7 @@ class Vtracert:
|
51
|
78
|
self.height = height
|
52
|
79
|
#Colors
|
53
|
80
|
self.col = dict()
|
|
81
|
+ self.col['alpha'] = pygame.Color(0,0,0,0)
|
54
|
82
|
self.col['bg'] = pygame.Color(0,0,0)
|
55
|
83
|
self.col['map'] = pygame.Color(15,8,63)
|
56
|
84
|
self.col['prompt'] = pygame.Color(200,200,200)
|
|
@@ -58,11 +86,15 @@ class Vtracert:
|
58
|
86
|
self.col['cur_status'] = self.col['status']
|
59
|
87
|
self.col['cur_statusline'] = self.col['status']
|
60
|
88
|
self.col['trace_init'] = pygame.Color(0,0xf0,0)
|
|
89
|
+ self.col['trace_end'] = pygame.Color(0xee,0x33,0xee)
|
61
|
90
|
self.col['trace_hop'] = pygame.Color(0xf0,0xf0,0)
|
62
|
91
|
self.col['trace_trace'] = pygame.Color(0xf0,0,0)
|
63
|
92
|
self.col['trace_txt'] = pygame.Color(200, 200, 200, 125)
|
64
|
93
|
self.col['trace_txtsel'] = self.col['trace_hop']
|
65
|
94
|
self.col['trace_progress'] = pygame.Color(0,0xf0,0)
|
|
95
|
+ self.col['help_txt'] = pygame.Color(200,200,200)
|
|
96
|
+ self.col['help_title'] = pygame.Color(120,30,230)
|
|
97
|
+ self.col['help_bg'] = pygame.Color(0,0,0)
|
66
|
98
|
for n, c in cols:
|
67
|
99
|
self.col[n] = pygame.Color(c)
|
68
|
100
|
#Fonts
|
|
@@ -71,13 +103,18 @@ class Vtracert:
|
71
|
103
|
self.font['status'] = pygame.font.Font(None,20)
|
72
|
104
|
self.font['cur_status'] = self.col['status']
|
73
|
105
|
self.font['trace_txt'] = pygame.font.Font(None,20)
|
|
106
|
+
|
|
107
|
+ self.font['help_title'] = pygame.font.Font(None,48)
|
|
108
|
+ self.font['help_title'].set_underline(True);
|
|
109
|
+ self.font['help_title'].set_bold(True);
|
|
110
|
+
|
|
111
|
+ self.font['help'] = pygame.font.SysFont('monospace', 16)
|
74
|
112
|
for n, (ft,fs) in fonts:
|
75
|
113
|
self.font[n] = pygame.font.Font(ft,fs)
|
76
|
114
|
#Prompt options
|
77
|
115
|
self.promptText = promptText
|
78
|
116
|
self.inputText = defaultInput
|
79
|
|
-
|
80
|
|
-
|
|
117
|
+ self.inputText = '1.202.15.14'
|
81
|
118
|
|
82
|
119
|
#Event filtering
|
83
|
120
|
pygame.event.set_allowed(None)
|
|
@@ -91,19 +128,25 @@ class Vtracert:
|
91
|
128
|
self.surf['tracetxt'] = pygame.Surface((width, height),pygame.HWSURFACE | pygame.SRCALPHA)
|
92
|
129
|
self.surf['status'] = None
|
93
|
130
|
|
|
131
|
+ for s in self.surf:
|
|
132
|
+ if self.surf[s] != None:
|
|
133
|
+ self.surf[s].fill(self.col['alpha'])
|
|
134
|
+
|
|
135
|
+ self.help(0)
|
94
|
136
|
self.drawStatus('Loading...');
|
95
|
137
|
pygame.display.flip()
|
96
|
138
|
|
97
|
|
-
|
98
|
139
|
#Clipboard handling module initialisation
|
99
|
140
|
pygame.scrap.init()
|
100
|
141
|
|
101
|
142
|
#Keyboard vars
|
102
|
143
|
self.caps = False
|
|
144
|
+ self.ctrl = False
|
103
|
145
|
|
104
|
146
|
#Map info
|
105
|
147
|
self.trmap = vtracemap.TraceMap(self)
|
106
|
148
|
self.tracer = tracer.Tracer(self)
|
|
149
|
+
|
107
|
150
|
|
108
|
151
|
## Color accessor
|
109
|
152
|
# @param cname Color name
|
|
@@ -139,6 +182,96 @@ class Vtracert:
|
139
|
182
|
dopt[cname] = v
|
140
|
183
|
return dopt[cname]
|
141
|
184
|
|
|
185
|
+ ## Return the unicode representation of the combiation of ctrl+a letter key
|
|
186
|
+ @classmethod
|
|
187
|
+ def ctrlUnicode(classo, c):
|
|
188
|
+ return unicode(chr(ord(c.lower())-ord('a')+1))
|
|
189
|
+ pass
|
|
190
|
+
|
|
191
|
+ ##Display an help on the screen and wait for an KEYDOWN or QUIT event
|
|
192
|
+ def help(self, ttl = None):
|
|
193
|
+ scr = self.surf['screen']
|
|
194
|
+ helpTxts = [
|
|
195
|
+ "Vtraceroute help",
|
|
196
|
+ "",
|
|
197
|
+ "Vtraceroute is a traceroute program ( more info : man traceroute )",
|
|
198
|
+ "that displays hops on a map using geoipLookup.",
|
|
199
|
+ "",
|
|
200
|
+ "Controls summary :",
|
|
201
|
+ "",
|
|
202
|
+ "^h, ? : display this help",
|
|
203
|
+ "esc, ^q : exit the programm or this help",
|
|
204
|
+ "",
|
|
205
|
+ "[a-zA-Z0-9\.] : Host input",
|
|
206
|
+ "mid-mouse btn : paste clipboard into host input",
|
|
207
|
+ "enter : validate host input and",
|
|
208
|
+ " run traceroute",
|
|
209
|
+ "^c : clear host input",
|
|
210
|
+ "",
|
|
211
|
+ "",
|
|
212
|
+ "mouse scroll, +, - : zoom in/out",
|
|
213
|
+ "arrow keys : move on the map",
|
|
214
|
+ "left mouse btn press : select hops on the map",
|
|
215
|
+ "","","",
|
|
216
|
+ "Press any key or mouse button to exit this help"
|
|
217
|
+ ]
|
|
218
|
+
|
|
219
|
+ tFont = self.font['help_title']
|
|
220
|
+ hFont = self.font['help']
|
|
221
|
+ hCol = self.col['help_txt']
|
|
222
|
+ tCol = self.col['help_title']
|
|
223
|
+
|
|
224
|
+ ty = 50
|
|
225
|
+ lspacing = 3
|
|
226
|
+ hy = ty + tFont.get_linesize() + lspacing
|
|
227
|
+ hx = 40
|
|
228
|
+
|
|
229
|
+ #Fill screen
|
|
230
|
+ scr.fill(self.col['help_bg'])
|
|
231
|
+
|
|
232
|
+ #Print title
|
|
233
|
+ titleTxt = helpTxts.pop(0)
|
|
234
|
+ tsurf = tFont.render(titleTxt,1,tCol)
|
|
235
|
+
|
|
236
|
+ tsc = tsurf.get_rect()
|
|
237
|
+ tsc.centerx = self.width/2 #center the title
|
|
238
|
+ tsc.y = ty
|
|
239
|
+
|
|
240
|
+ scr.blit(tsurf,tsc)
|
|
241
|
+
|
|
242
|
+ #Print help text
|
|
243
|
+ for line in helpTxts:
|
|
244
|
+
|
|
245
|
+ if len(line) > 0:
|
|
246
|
+ tsurf = hFont.render(line,1,hCol)
|
|
247
|
+ scr.blit(tsurf,(hx, hy))
|
|
248
|
+
|
|
249
|
+ hy += hFont.get_linesize()
|
|
250
|
+ hy += lspacing
|
|
251
|
+ #pygame.display.flip();time.sleep(0.05);
|
|
252
|
+
|
|
253
|
+ pygame.display.flip()
|
|
254
|
+
|
|
255
|
+ if ttl == None:
|
|
256
|
+ wait = True
|
|
257
|
+ while wait:
|
|
258
|
+ evts = pygame.event.get()
|
|
259
|
+ for evt in evts:
|
|
260
|
+ if evt.type in (pygame.QUIT, pygame.KEYDOWN, pygame.MOUSEBUTTONUP):
|
|
261
|
+ wait = False
|
|
262
|
+ break;
|
|
263
|
+ else:
|
|
264
|
+ time.sleep(ttl)
|
|
265
|
+ pass
|
|
266
|
+
|
|
267
|
+ """
|
|
268
|
+ ## Return True
|
|
269
|
+ # @c1 unicode1
|
|
270
|
+ # @c2 unicode2
|
|
271
|
+ def isCtrlUnicode(self, c, cu):
|
|
272
|
+ return (self.ctrl and Vtracert.ctrlUnicode(c) == cu)
|
|
273
|
+ """
|
|
274
|
+
|
142
|
275
|
## Blit a surface on the screen surface
|
143
|
276
|
# @param sname The surface name
|
144
|
277
|
# @param pos A tuple (x,y) for the blit position
|
|
@@ -146,15 +279,22 @@ class Vtracert:
|
146
|
279
|
def blitScreen(self, sname, pos = (0,0) ):
|
147
|
280
|
return self.surf['screen'].blit(self.surf[sname], pos)
|
148
|
281
|
|
|
282
|
+ ## Draw the map again and call Vtracert::flip()
|
|
283
|
+ # Call Vtracert::fillScreen()
|
|
284
|
+ # @see Vtracert::fillScreen(), Vtracert::flip()
|
149
|
285
|
def mapRedraw(self):
|
150
|
286
|
self.fillScreen()
|
151
|
287
|
self.trmap.draw()
|
152
|
288
|
self.flip()
|
153
|
289
|
|
|
290
|
+ ## Fill the screen with the 'bg' color
|
154
|
291
|
def fillScreen(self):
|
155
|
292
|
self.surf['screen'].fill(self.col['bg'])
|
156
|
293
|
pass
|
157
|
294
|
|
|
295
|
+ ## Blit all the surface is the right order but don't call pygame.display.flip()
|
|
296
|
+ # The status bar horizontal ruler is a draw and not a blit
|
|
297
|
+ # @see Vtracert::flip()
|
158
|
298
|
def blit(self):
|
159
|
299
|
self.blitScreen('map')
|
160
|
300
|
self.blitScreen('status')
|
|
@@ -164,6 +304,7 @@ class Vtracert:
|
164
|
304
|
pass
|
165
|
305
|
|
166
|
306
|
## Blit all surface and flip display
|
|
307
|
+ # @see Vtracert::blit()
|
167
|
308
|
def flip(self, fill = True):
|
168
|
309
|
if fill:
|
169
|
310
|
self.fillScreen()
|
|
@@ -199,7 +340,7 @@ class Vtracert:
|
199
|
340
|
|
200
|
341
|
self.surf['status'] = font.render(statusText, antialiasing, col)
|
201
|
342
|
|
202
|
|
- #self.blitScreen('status')
|
|
343
|
+ self.blitScreen('status')
|
203
|
344
|
|
204
|
345
|
if line:
|
205
|
346
|
self.drawStatusLine()
|
|
@@ -218,20 +359,33 @@ class Vtracert:
|
218
|
359
|
def keyupEvt(self, evt):
|
219
|
360
|
if evt.key == 303 or evt.key == 304: #caps release
|
220
|
361
|
self.caps = False
|
221
|
|
- print "Caps released"
|
|
362
|
+ elif evt.key == 305 or evt.key == 306: #ctrl release
|
|
363
|
+ self.ctrl = False
|
222
|
364
|
pass
|
223
|
365
|
|
224
|
366
|
## Handles a KEYDOWN event
|
225
|
367
|
# @param evt Event
|
226
|
368
|
def keydownEvt(self, evt):
|
227
|
369
|
ccode = evt.key
|
228
|
|
-
|
|
370
|
+
|
|
371
|
+ c2u = Vtracert.ctrlUnicode
|
|
372
|
+
|
229
|
373
|
allowedChar = range(ord('a'),ord('z')+1)
|
230
|
374
|
allowedChar += range(ord('A'),ord('Z')+1)
|
231
|
375
|
allowedChar += range(ord('0'),ord('9')+1)
|
232
|
376
|
allowedChar += [ord('.'),ord('\b'),ord('\r'),ord('\n')]
|
233
|
377
|
|
234
|
378
|
allowedChar = [ chr(cc) for cc in allowedChar ]
|
|
379
|
+ ctrlChar = [ c2u('q'), #^q
|
|
380
|
+ c2u('h'), #^h
|
|
381
|
+ c2u('n'), #^n
|
|
382
|
+ c2u('c'), #^n
|
|
383
|
+ '?',
|
|
384
|
+ u'\x1b' #escape button
|
|
385
|
+ ]
|
|
386
|
+
|
|
387
|
+ #print evt
|
|
388
|
+ #print self.ctrl
|
235
|
389
|
|
236
|
390
|
if ccode in [273,274,275,276]: #Arrow keys
|
237
|
391
|
if ccode == 273:
|
|
@@ -244,17 +398,43 @@ class Vtracert:
|
244
|
398
|
d = 'left'
|
245
|
399
|
|
246
|
400
|
self.trmap.zoom( (None, None), d)
|
|
401
|
+ self.tracer.drawTrace(0)
|
|
402
|
+ self.flip()
|
|
403
|
+ pygame.event.clear(pygame.MOUSEBUTTONUP)
|
247
|
404
|
|
248
|
405
|
elif ccode == 303 or ccode == 304: #caps
|
249
|
|
- caps = True
|
250
|
|
- elif evt.unicode in allowedChar:
|
|
406
|
+ self.caps = True
|
|
407
|
+ elif evt.key == 305 or evt.key == 306: #ctrl release
|
|
408
|
+ self.ctrl = True
|
|
409
|
+ elif self.ctrl or cc in ctrlChar: # ctrl + key handle
|
251
|
410
|
|
|
411
|
+ cc = evt.unicode
|
|
412
|
+ if cc == u'\x1b' or cc == c2u('q'): #quit (esc or ^q)
|
|
413
|
+ pygame.event.post(pygame.event.Event(pygame.QUIT))
|
|
414
|
+ elif cc == c2u('h') or cc == '?': #help ^h ? ^?
|
|
415
|
+ print "Help !!!!!!!!"
|
|
416
|
+ self.help()
|
|
417
|
+ self.flip()
|
|
418
|
+ elif cc == c2u('c'):
|
|
419
|
+ self.inputText = ''
|
|
420
|
+ self.drawPrompt()
|
|
421
|
+ elif cc == c2u('n'):
|
|
422
|
+ for cname in self.col:
|
|
423
|
+ c = self.col[cname]
|
|
424
|
+ c.r = 255 - c.r
|
|
425
|
+ c.g = 255 - c.g
|
|
426
|
+ c.b = 255 - c.b
|
|
427
|
+ self.col[cname] = c
|
|
428
|
+ self.mapRedraw()
|
|
429
|
+
|
|
430
|
+ elif evt.unicode in allowedChar:
|
252
|
431
|
|
253
|
|
- cinput = evt.unicode
|
254
|
|
- if cinput == '\b':
|
|
432
|
+ cc = evt.unicode
|
|
433
|
+
|
|
434
|
+ if cc == '\b': #backspace
|
255
|
435
|
if len(self.inputText) > 0:
|
256
|
436
|
self.inputText = self.inputText[:-1]
|
257
|
|
- elif cinput == '\r' or cinput == '\n':
|
|
437
|
+ elif cc == '\r' or cc == '\n':
|
258
|
438
|
print "OK, tracerouting %s ..."%self.inputText
|
259
|
439
|
dest = self.inputText
|
260
|
440
|
self.inputText = ""
|
|
@@ -266,7 +446,7 @@ class Vtracert:
|
266
|
446
|
self.flip()
|
267
|
447
|
|
268
|
448
|
else:
|
269
|
|
- self.inputText += cinput
|
|
449
|
+ self.inputText += cc
|
270
|
450
|
|
271
|
451
|
self.drawPrompt()
|
272
|
452
|
pass
|
|
@@ -282,8 +462,9 @@ class Vtracert:
|
282
|
462
|
zoom = False
|
283
|
463
|
|
284
|
464
|
self.trmap.zoom(evt.pos,zoom)
|
285
|
|
- self.tracer.drawTrace()
|
|
465
|
+ self.tracer.drawTrace(0)
|
286
|
466
|
self.blit()
|
|
467
|
+ pygame.event.clear(pygame.MOUSEBUTTONUP)
|
287
|
468
|
#end scrollzoom
|
288
|
469
|
|
289
|
470
|
elif evt.button == 1:
|
|
@@ -302,6 +483,7 @@ class Vtracert:
|
302
|
483
|
types = pygame.scrap.get_types()
|
303
|
484
|
for t in types:
|
304
|
485
|
print t,pygame.scrap.get(t)
|
|
486
|
+
|
305
|
487
|
pass
|
306
|
488
|
|
307
|
489
|
|
|
@@ -312,23 +494,32 @@ class Vtracert:
|
312
|
494
|
self.mapRedraw();
|
313
|
495
|
self.flip()
|
314
|
496
|
|
|
497
|
+ #Display small onetime help text
|
|
498
|
+ htext = self.font['status'].render("Type ^h or ? for help.",1, self.col['status'])
|
|
499
|
+ self.surf['screen'].blit(htext, (5, self.font['status'].get_linesize()+2))
|
|
500
|
+ pygame.display.flip()
|
|
501
|
+
|
315
|
502
|
again = True
|
316
|
503
|
|
317
|
504
|
while again:
|
|
505
|
+ """
|
318
|
506
|
evts = pygame.event.get()
|
319
|
507
|
if len(evts) > 0:
|
320
|
508
|
|
321
|
509
|
for evt in evts:
|
322
|
|
- if evt.type == pygame.QUIT:
|
323
|
|
- again = False
|
324
|
|
- break
|
325
|
|
- elif evt.type == pygame.KEYUP:
|
326
|
|
- self.keyupEvt(evt)
|
327
|
|
- elif evt.type == pygame.KEYDOWN:
|
328
|
|
- self.keydownEvt(evt)
|
329
|
|
- elif evt.type == pygame.MOUSEBUTTONUP:
|
330
|
|
- self.mouseboutonupEvt(evt)
|
331
|
|
-
|
332
|
|
- self.drawPrompt();
|
333
|
|
- self.flip()
|
|
510
|
+ """
|
|
511
|
+ evt = pygame.event.wait()
|
|
512
|
+ if evt != pygame.NOEVENT:
|
|
513
|
+ if evt.type == pygame.QUIT:
|
|
514
|
+ again = False
|
|
515
|
+ break
|
|
516
|
+ elif evt.type == pygame.KEYUP:
|
|
517
|
+ self.keyupEvt(evt)
|
|
518
|
+ elif evt.type == pygame.KEYDOWN:
|
|
519
|
+ self.keydownEvt(evt)
|
|
520
|
+ elif evt.type == pygame.MOUSEBUTTONUP:
|
|
521
|
+ self.mouseboutonupEvt(evt)
|
|
522
|
+
|
|
523
|
+ self.drawPrompt();
|
|
524
|
+ self.flip()
|
334
|
525
|
|