| 1 | #!/usr/bin/env python |
|---|
| 2 | # -*- coding: utf-8 -*- |
|---|
| 3 | # Copyright (C) 2008 Adriano Monteiro Marques |
|---|
| 4 | # |
|---|
| 5 | # Author: Francesco Piccinno <stack.box@gmail.com> |
|---|
| 6 | # |
|---|
| 7 | # This program is free software; you can redistribute it and/or modify |
|---|
| 8 | # it under the terms of the GNU General Public License as published by |
|---|
| 9 | # the Free Software Foundation; either version 2 of the License, or |
|---|
| 10 | # (at your option) any later version. |
|---|
| 11 | # |
|---|
| 12 | # This program is distributed in the hope that it will be useful, |
|---|
| 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 | # GNU General Public License for more details. |
|---|
| 16 | # |
|---|
| 17 | # You should have received a copy of the GNU General Public License |
|---|
| 18 | # along with this program; if not, write to the Free Software |
|---|
| 19 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 20 | |
|---|
| 21 | """ |
|---|
| 22 | This module contains the MainWindow class |
|---|
| 23 | """ |
|---|
| 24 | |
|---|
| 25 | import gtk |
|---|
| 26 | import os |
|---|
| 27 | |
|---|
| 28 | from PM import Backend |
|---|
| 29 | from PM.Core.Logger import log |
|---|
| 30 | from PM.Manager.PreferenceManager import Prefs |
|---|
| 31 | |
|---|
| 32 | from PM.Gui.Widgets.StatusBar import StatusBar |
|---|
| 33 | from PM.higwidgets.higdialogs import HIGAlertDialog |
|---|
| 34 | |
|---|
| 35 | __paned_imported = False |
|---|
| 36 | |
|---|
| 37 | if Prefs()['gui.docking'].value.lower() == 'moo': |
|---|
| 38 | try: |
|---|
| 39 | from MooPaned import * |
|---|
| 40 | __paned_imported = True |
|---|
| 41 | except ImportError: |
|---|
| 42 | log.info("moo library is not installed.") |
|---|
| 43 | |
|---|
| 44 | elif Prefs()['gui.docking'].value.lower() == 'gdl': |
|---|
| 45 | try: |
|---|
| 46 | from GdlPaned import * |
|---|
| 47 | __paned_imported = True |
|---|
| 48 | except ImportError: |
|---|
| 49 | log.info("GDL is not installed. Using fallback paned.") |
|---|
| 50 | |
|---|
| 51 | if Prefs()['gui.docking'].value.lower() == 'standard' or not __paned_imported: |
|---|
| 52 | from FallbackPaned import * |
|---|
| 53 | __paned_imported = True |
|---|
| 54 | |
|---|
| 55 | log.info('Using fallback paned') |
|---|
| 56 | |
|---|
| 57 | from PM.Gui.Tabs.VteTab import VteTab |
|---|
| 58 | from PM.Gui.Tabs.MainTab import MainTab |
|---|
| 59 | from PM.Gui.Tabs.HackTab import HackTab |
|---|
| 60 | from PM.Gui.Tabs.StatusTab import StatusTab |
|---|
| 61 | from PM.Gui.Tabs.ConsoleTab import ConsoleTab |
|---|
| 62 | from PM.Gui.Tabs.PropertyTab import PropertyTab |
|---|
| 63 | from PM.Gui.Tabs.OperationsTab import OperationsTab, SniffOperation |
|---|
| 64 | from PM.Gui.Tabs.OperationsTab import FileOperation |
|---|
| 65 | from PM.Gui.Tabs.ProtocolSelectorTab import ProtocolSelectorTab |
|---|
| 66 | |
|---|
| 67 | from PM.Gui.Dialogs.Interface import InterfaceDialog |
|---|
| 68 | from PM.Gui.Dialogs.Preferences import PreferenceDialog |
|---|
| 69 | from PM.Gui.Dialogs.Routes import RoutesDialog |
|---|
| 70 | from PM.Gui.Plugins.Window import PluginWindow |
|---|
| 71 | |
|---|
| 72 | from PM.Gui.Pages import PerspectiveType |
|---|
| 73 | |
|---|
| 74 | from PM.Gui.Sessions.Base import Session |
|---|
| 75 | from PM.Gui.Sessions import SessionType |
|---|
| 76 | |
|---|
| 77 | from PM.Core.I18N import _ |
|---|
| 78 | from PM.Core.Const import PM_DEVELOPMENT, PM_SVN_REVISION |
|---|
| 79 | from PM.Core.Const import PIXMAPS_DIR, PM_VERSION, PM_SITE |
|---|
| 80 | |
|---|
| 81 | class MainWindow(gtk.Window): |
|---|
| 82 | def __init__(self): |
|---|
| 83 | gtk.Window.__init__(self) |
|---|
| 84 | |
|---|
| 85 | self.set_title("Packet Manipulator") |
|---|
| 86 | self.set_icon_from_file(os.path.join(PIXMAPS_DIR, 'pm-logo.png')) |
|---|
| 87 | self.set_default_size(600, 400) |
|---|
| 88 | |
|---|
| 89 | self.registered_tabs = {} |
|---|
| 90 | |
|---|
| 91 | # Binders for plugins |
|---|
| 92 | self.perspective_binder = [] |
|---|
| 93 | self.session_binder = [] |
|---|
| 94 | |
|---|
| 95 | for i in PerspectiveType.types: |
|---|
| 96 | self.perspective_binder.append(list()) |
|---|
| 97 | |
|---|
| 98 | for i in SessionType.types: |
|---|
| 99 | self.session_binder.append(list()) |
|---|
| 100 | |
|---|
| 101 | self.perspective_binder = tuple(self.perspective_binder) |
|---|
| 102 | self.session_binder = tuple(self.session_binder) |
|---|
| 103 | |
|---|
| 104 | self.__create_widgets() |
|---|
| 105 | self.__pack_widgets() |
|---|
| 106 | self.__connect_signals() |
|---|
| 107 | |
|---|
| 108 | self.statusbar.push(_("Ready."), image=gtk.STOCK_YES) |
|---|
| 109 | |
|---|
| 110 | self.show_all() |
|---|
| 111 | |
|---|
| 112 | def __create_widgets(self): |
|---|
| 113 | "Create widgets" |
|---|
| 114 | |
|---|
| 115 | self.main_actions = [ |
|---|
| 116 | ('File', None, _('File'), None), |
|---|
| 117 | |
|---|
| 118 | ('NewSequence', gtk.STOCK_NEW, _('_New sequence'), '<Control>n', |
|---|
| 119 | _('Create a new sequence'), self.__on_new_sequence), |
|---|
| 120 | |
|---|
| 121 | ('Open', gtk.STOCK_OPEN, _('_Open'), '<Control>o', |
|---|
| 122 | _('Open session'), self.__on_open_session), |
|---|
| 123 | |
|---|
| 124 | ('Save', gtk.STOCK_SAVE, _('_Save'), '<Control>s', |
|---|
| 125 | _('Save session'), self.__on_save_session), |
|---|
| 126 | |
|---|
| 127 | ('SaveAs', gtk.STOCK_SAVE_AS, _('_Save as'), '<Control><Shift>s', |
|---|
| 128 | _('Save session as'), self.__on_save_session_as), |
|---|
| 129 | |
|---|
| 130 | ('Quit', gtk.STOCK_QUIT, _('_Quit'), '<Control>q', |
|---|
| 131 | _('Quit from application'), self.__on_quit), |
|---|
| 132 | |
|---|
| 133 | ('Capture', None, _('Capture'), None), |
|---|
| 134 | |
|---|
| 135 | ('Interface', gtk.STOCK_CONNECT, _('_Interface'), '<Control>i', |
|---|
| 136 | _('Capture from interface'), self.__on_select_iface), |
|---|
| 137 | |
|---|
| 138 | ('Options', None, _('Options'), None), |
|---|
| 139 | |
|---|
| 140 | ('Routes', gtk.STOCK_NETWORK, _('Routing table'), '<Control>r', |
|---|
| 141 | _('Routes editor'), self.__on_routing), |
|---|
| 142 | |
|---|
| 143 | ('Plugins', 'extension_small', _('Plugins'), None, |
|---|
| 144 | _('Plugin manager'), self.__on_plugins), |
|---|
| 145 | |
|---|
| 146 | ('Preferences', gtk.STOCK_PREFERENCES, _('_Preferences'), |
|---|
| 147 | '<Control>p', _('Preferences'), self.__on_preferences), |
|---|
| 148 | |
|---|
| 149 | ('Views', None, _('Views'), None), |
|---|
| 150 | |
|---|
| 151 | ('Help', None, _('Help'), None), |
|---|
| 152 | |
|---|
| 153 | ('About', gtk.STOCK_ABOUT, _('About'), None, None, self.__on_about), |
|---|
| 154 | ] |
|---|
| 155 | |
|---|
| 156 | self.default_ui = """<menubar> |
|---|
| 157 | <menu action='File'> |
|---|
| 158 | <menuitem action='NewSequence'/> |
|---|
| 159 | <menuitem action='Open'/> |
|---|
| 160 | <menuitem action='Save'/> |
|---|
| 161 | <menuitem action='SaveAs'/> |
|---|
| 162 | <separator/> |
|---|
| 163 | <menuitem action='Quit'/> |
|---|
| 164 | </menu> |
|---|
| 165 | <menu action='Capture'> |
|---|
| 166 | <menuitem action='Interface'/> |
|---|
| 167 | </menu> |
|---|
| 168 | <menu action='Options'> |
|---|
| 169 | <menuitem action='Routes'/> |
|---|
| 170 | <separator/> |
|---|
| 171 | <menuitem action='Plugins'/> |
|---|
| 172 | <separator/> |
|---|
| 173 | <menuitem action='Preferences'/> |
|---|
| 174 | </menu> |
|---|
| 175 | <menu action='Views'/> |
|---|
| 176 | <menu action='Help'> |
|---|
| 177 | <menuitem action='About'/> |
|---|
| 178 | </menu> |
|---|
| 179 | </menubar> |
|---|
| 180 | |
|---|
| 181 | <toolbar> |
|---|
| 182 | <toolitem action='Open'/> |
|---|
| 183 | <toolitem action='Save'/> |
|---|
| 184 | <toolitem action='Interface'/> |
|---|
| 185 | <separator/> |
|---|
| 186 | <toolitem action='Routes'/> |
|---|
| 187 | <toolitem action='Preferences'/> |
|---|
| 188 | <separator/> |
|---|
| 189 | </toolbar> |
|---|
| 190 | """ |
|---|
| 191 | |
|---|
| 192 | self.ui_manager = gtk.UIManager() |
|---|
| 193 | |
|---|
| 194 | self.main_accel_group = gtk.AccelGroup() |
|---|
| 195 | self.main_action_group = gtk.ActionGroup('MainActionGroup') |
|---|
| 196 | self.main_action_group.add_actions(self.main_actions) |
|---|
| 197 | |
|---|
| 198 | self.add_accel_group(self.main_accel_group) |
|---|
| 199 | |
|---|
| 200 | for action in self.main_action_group.list_actions(): |
|---|
| 201 | action.set_accel_group(self.main_accel_group) |
|---|
| 202 | action.connect_accelerator() |
|---|
| 203 | |
|---|
| 204 | self.ui_manager.insert_action_group(self.main_action_group, 0) |
|---|
| 205 | self.ui_manager.add_ui_from_string(self.default_ui) |
|---|
| 206 | |
|---|
| 207 | # Central widgets |
|---|
| 208 | self.main_paned = UmitPaned() |
|---|
| 209 | |
|---|
| 210 | self.vbox = gtk.VBox(False, 2) |
|---|
| 211 | self.statusbar = StatusBar() |
|---|
| 212 | |
|---|
| 213 | self.plugin_window = PluginWindow() |
|---|
| 214 | |
|---|
| 215 | def get_tab(self, name): |
|---|
| 216 | """ |
|---|
| 217 | Get a tab from its name |
|---|
| 218 | |
|---|
| 219 | @param name the name of the tab |
|---|
| 220 | """ |
|---|
| 221 | |
|---|
| 222 | return self.registered_tabs[name] |
|---|
| 223 | |
|---|
| 224 | def deregister_tab(self, tab): |
|---|
| 225 | """ |
|---|
| 226 | Deregister a tab deleting his CheckMenu and tab from the paned |
|---|
| 227 | |
|---|
| 228 | @param tab the tab to deregister |
|---|
| 229 | @return True if is ok or False |
|---|
| 230 | """ |
|---|
| 231 | |
|---|
| 232 | item = self.ui_manager.get_widget('/menubar/Views') |
|---|
| 233 | menu = item.get_submenu() |
|---|
| 234 | |
|---|
| 235 | def find_tab(item, udata): |
|---|
| 236 | tab, find = udata |
|---|
| 237 | |
|---|
| 238 | if item.get_data('tab-object') is tab: |
|---|
| 239 | find = item |
|---|
| 240 | return True |
|---|
| 241 | |
|---|
| 242 | find = None |
|---|
| 243 | menu.foreach(find_tab, (tab, find)) |
|---|
| 244 | |
|---|
| 245 | if find is not None: |
|---|
| 246 | menu.remove(find) |
|---|
| 247 | self.main_paned.remove_view(tab) |
|---|
| 248 | del self.registered_tabs[tab.name] |
|---|
| 249 | |
|---|
| 250 | return True |
|---|
| 251 | |
|---|
| 252 | return False |
|---|
| 253 | |
|---|
| 254 | def register_tab(self, tab, show=True): |
|---|
| 255 | """ |
|---|
| 256 | Register a tab |
|---|
| 257 | |
|---|
| 258 | @param tab the Tab object |
|---|
| 259 | @param show if the Tab should be showed |
|---|
| 260 | """ |
|---|
| 261 | |
|---|
| 262 | item = self.ui_manager.get_widget('/menubar/Views') |
|---|
| 263 | menu = item.get_submenu() |
|---|
| 264 | |
|---|
| 265 | item.show() |
|---|
| 266 | |
|---|
| 267 | if not menu: |
|---|
| 268 | menu = gtk.Menu() |
|---|
| 269 | item.set_submenu(menu) |
|---|
| 270 | |
|---|
| 271 | if tab.name in self.registered_tabs: |
|---|
| 272 | raise Exception("Tab already present") |
|---|
| 273 | |
|---|
| 274 | # Ok we should add a CheckMenuItem to this fucking menu |
|---|
| 275 | self.registered_tabs[tab.name] = tab |
|---|
| 276 | |
|---|
| 277 | log.debug("Tab %s registered as %s" % (tab.label_text, tab.name)) |
|---|
| 278 | |
|---|
| 279 | if tab.tab_position is None: |
|---|
| 280 | # This is the central widget so it should be added |
|---|
| 281 | # with no MenuItem |
|---|
| 282 | self.main_paned.add_view(tab) |
|---|
| 283 | return |
|---|
| 284 | |
|---|
| 285 | new_item = gtk.CheckMenuItem(tab.label_text) |
|---|
| 286 | new_item.set_data('tab-object', tab) |
|---|
| 287 | new_item.connect('toggled', self.__on_toggle_tab_menu, tab) |
|---|
| 288 | |
|---|
| 289 | if show: |
|---|
| 290 | new_item.set_active(True) |
|---|
| 291 | |
|---|
| 292 | new_item.show() |
|---|
| 293 | menu.append(new_item) |
|---|
| 294 | |
|---|
| 295 | def create_session(self, menu, tuple): |
|---|
| 296 | """ |
|---|
| 297 | Create a new session using ctxklass and sessklass |
|---|
| 298 | |
|---|
| 299 | @param menu gtk.MenuItem |
|---|
| 300 | @param tuple a tuple containing (sessklass, ctxklass) |
|---|
| 301 | """ |
|---|
| 302 | sessklass, ctxklass = tup |
|---|
| 303 | maintab = self.get_tab("MainTab") |
|---|
| 304 | maintab.session_notebook.create_session(sessklass, ctxklass) |
|---|
| 305 | |
|---|
| 306 | def register_session(self, sessklass, ctxklass=None): |
|---|
| 307 | """ |
|---|
| 308 | Register a custom session class and returns the new id |
|---|
| 309 | of the SessionType |
|---|
| 310 | |
|---|
| 311 | @param sessklass the custom session class |
|---|
| 312 | @param ctxklass the context class to use |
|---|
| 313 | @return id |
|---|
| 314 | """ |
|---|
| 315 | |
|---|
| 316 | if sessklass.session_menu is not None: |
|---|
| 317 | item = self.ui_manager.get_widget('/menubar/File') |
|---|
| 318 | menu = item.get_submenu() |
|---|
| 319 | |
|---|
| 320 | item = gtk.MenuItem(sessklass.session_menu) |
|---|
| 321 | item.connect('activate', self.create_session, (sessklass, ctxklass)) |
|---|
| 322 | item.show() |
|---|
| 323 | |
|---|
| 324 | menu.insert(item, 2) |
|---|
| 325 | |
|---|
| 326 | sessklass.session_menu_object = item |
|---|
| 327 | |
|---|
| 328 | return SessionType.add_session(sessklass) |
|---|
| 329 | |
|---|
| 330 | def deregister_session(self, sessklass): |
|---|
| 331 | if sessklass.session_menu_object: |
|---|
| 332 | menu = self.ui_manager.get_widget('/menubar/File').get_submenu() |
|---|
| 333 | sessklass.session_menu_object.hide() |
|---|
| 334 | |
|---|
| 335 | menu.remove(sessklass.session_menu_object) |
|---|
| 336 | |
|---|
| 337 | return SessionType.remove_session(sessklass) |
|---|
| 338 | |
|---|
| 339 | def bind_session(self, ptype, persp_klass, show_pers=True, resize=False, \ |
|---|
| 340 | shrink=True): |
|---|
| 341 | """ |
|---|
| 342 | Bind the perspective 'pers_klass' to Session 'ptype' |
|---|
| 343 | |
|---|
| 344 | @param ptype the Session type to customize |
|---|
| 345 | @param persp_klass the perspective class to add to the selected Session |
|---|
| 346 | @param show_pers choose to show the perspective |
|---|
| 347 | @param resize if True child should resize when the paned is resized |
|---|
| 348 | @param shrink if True child can be made smaller than its minimum size |
|---|
| 349 | request |
|---|
| 350 | """ |
|---|
| 351 | |
|---|
| 352 | log.debug( |
|---|
| 353 | "Binding perspective %s to Session %s" % \ |
|---|
| 354 | (persp_klass, SessionType.types[ptype]) |
|---|
| 355 | ) |
|---|
| 356 | |
|---|
| 357 | self.session_binder[ptype].append((persp_klass, show_pers, \ |
|---|
| 358 | resize, shrink)) |
|---|
| 359 | |
|---|
| 360 | klass = SessionType.types[ptype] |
|---|
| 361 | maintab = self.get_tab("MainTab") |
|---|
| 362 | |
|---|
| 363 | for page in maintab.session_notebook: |
|---|
| 364 | if isinstance(page, klass): |
|---|
| 365 | self.apply_bindings(page, ptype) |
|---|
| 366 | |
|---|
| 367 | def unbind_session(self, type, persp_klass): |
|---|
| 368 | try: |
|---|
| 369 | for i in range(len(self.session_binder[ptype])): |
|---|
| 370 | (klass, show, resize, shrink) = self.session_binder[ptype][i] |
|---|
| 371 | |
|---|
| 372 | if klass is not persp_klass: |
|---|
| 373 | continue |
|---|
| 374 | |
|---|
| 375 | del self.session_binder[type][i] |
|---|
| 376 | |
|---|
| 377 | klass = SessionType.types[type] |
|---|
| 378 | maintab = self.get_tab("MainTab") |
|---|
| 379 | |
|---|
| 380 | for page in maintab.session_notebook: |
|---|
| 381 | if isinstance(page, klass): |
|---|
| 382 | page.remove_perspective(klass) |
|---|
| 383 | |
|---|
| 384 | log.debug( |
|---|
| 385 | "Binding method %s for perspective of type %s removed" % \ |
|---|
| 386 | (persp_klass, SessionType.types[type]) |
|---|
| 387 | ) |
|---|
| 388 | |
|---|
| 389 | return True |
|---|
| 390 | except: |
|---|
| 391 | log.error( |
|---|
| 392 | "Failed to remove binding method %s for session of type %s" % \ |
|---|
| 393 | (persp_klass, SessionType.type[ptype]) |
|---|
| 394 | ) |
|---|
| 395 | |
|---|
| 396 | return False |
|---|
| 397 | |
|---|
| 398 | def apply_bindings(self, page, ptype): |
|---|
| 399 | for persp_klass, show, resize, shrink in self.session_binder[ptype]: |
|---|
| 400 | page.add_perspective(persp_klass, show, resize, shrink) |
|---|
| 401 | |
|---|
| 402 | def bind_perspective(self, ptype, callback): |
|---|
| 403 | """ |
|---|
| 404 | Bind the perspective 'type' |
|---|
| 405 | |
|---|
| 406 | The callback should be of the type |
|---|
| 407 | def perspective_cb(perspective, type, already_present, added) |
|---|
| 408 | |
|---|
| 409 | @param type the perspective's type (see also PerspectiveType) |
|---|
| 410 | @param callback the callback to execute when a new |
|---|
| 411 | perspective of type 'type' is created |
|---|
| 412 | """ |
|---|
| 413 | |
|---|
| 414 | log.debug( |
|---|
| 415 | "Binding method %s for perspective of type %s" % \ |
|---|
| 416 | (callback, PerspectiveType.types[ptype]) |
|---|
| 417 | ) |
|---|
| 418 | |
|---|
| 419 | self.perspective_binder[ptype].append(callback) |
|---|
| 420 | |
|---|
| 421 | maintab = self.get_tab("MainTab") |
|---|
| 422 | |
|---|
| 423 | for page in maintab.session_notebook: |
|---|
| 424 | for perspective in page.perspectives: |
|---|
| 425 | idx = PerspectiveType.types[type(perspective)] |
|---|
| 426 | |
|---|
| 427 | callback(perspective, idx, True, True) |
|---|
| 428 | |
|---|
| 429 | def debind_perspective(self, type, callback): |
|---|
| 430 | """ |
|---|
| 431 | Remove the binding callback for perspective of type 'type' |
|---|
| 432 | |
|---|
| 433 | @param type the perspective type |
|---|
| 434 | @param callback the callback to remove |
|---|
| 435 | @return True if the callback is removed correctly |
|---|
| 436 | """ |
|---|
| 437 | |
|---|
| 438 | try: |
|---|
| 439 | self.perspective_binder[type].remove(callback) |
|---|
| 440 | |
|---|
| 441 | maintab = self.get_tab("MainTab") |
|---|
| 442 | |
|---|
| 443 | for page in maintab.session_notebook: |
|---|
| 444 | for perspective in page.perspectives: |
|---|
| 445 | idx = PerspectiveType.types[type(perspective)] |
|---|
| 446 | |
|---|
| 447 | callback(perspective, idx, True, False) |
|---|
| 448 | |
|---|
| 449 | log.debug( |
|---|
| 450 | "Binding method %s for perspective of type %s removed" % \ |
|---|
| 451 | (callback, PerspectiveType.types[type]) |
|---|
| 452 | ) |
|---|
| 453 | |
|---|
| 454 | return True |
|---|
| 455 | except: |
|---|
| 456 | log.error( |
|---|
| 457 | "Failed to remove binding method %s " |
|---|
| 458 | "for perspective of type %s" % \ |
|---|
| 459 | (callback, PerspectiveType.types[type]) |
|---|
| 460 | ) |
|---|
| 461 | |
|---|
| 462 | return False |
|---|
| 463 | |
|---|
| 464 | def __pack_widgets(self): |
|---|
| 465 | "Pack widgets" |
|---|
| 466 | |
|---|
| 467 | self.menubar = self.ui_manager.get_widget("/menubar") |
|---|
| 468 | self.vbox.pack_start(self.menubar, False, False, 0) |
|---|
| 469 | |
|---|
| 470 | self.toolbar = self.ui_manager.get_widget("/toolbar") |
|---|
| 471 | self.toolbar.set_style(gtk.TOOLBAR_ICONS) |
|---|
| 472 | |
|---|
| 473 | self.vbox.pack_start(self.toolbar, False, False, 0) |
|---|
| 474 | |
|---|
| 475 | item = self.ui_manager.get_widget('/menubar/Views') |
|---|
| 476 | item.remove_submenu() |
|---|
| 477 | |
|---|
| 478 | self.vbox.pack_start(self.main_paned) |
|---|
| 479 | self.vbox.pack_start(self.statusbar, False, False) |
|---|
| 480 | |
|---|
| 481 | # Tabs |
|---|
| 482 | self.register_tab(MainTab()) |
|---|
| 483 | |
|---|
| 484 | self.register_tab(ProtocolSelectorTab(), |
|---|
| 485 | Prefs()['gui.views.protocol_selector_tab'].value) |
|---|
| 486 | self.register_tab(PropertyTab(), |
|---|
| 487 | Prefs()['gui.views.property_tab'].value) |
|---|
| 488 | self.register_tab(StatusTab(), |
|---|
| 489 | Prefs()['gui.views.status_tab'].value) |
|---|
| 490 | self.register_tab(OperationsTab(), |
|---|
| 491 | Prefs()['gui.views.operations_tab'].value) |
|---|
| 492 | self.register_tab(VteTab(), |
|---|
| 493 | Prefs()['gui.views.vte_tab'].value) |
|---|
| 494 | self.register_tab(HackTab(), |
|---|
| 495 | Prefs()['gui.views.hack_tab'].value) |
|---|
| 496 | self.register_tab(ConsoleTab(), |
|---|
| 497 | Prefs()['gui.views.console_tab'].value) |
|---|
| 498 | |
|---|
| 499 | self.add(self.vbox) |
|---|
| 500 | |
|---|
| 501 | def __connect_signals(self): |
|---|
| 502 | "Connect signals" |
|---|
| 503 | self.connect('delete-event', self.__on_quit) |
|---|
| 504 | |
|---|
| 505 | # Ok we need also to connect signals from main notebook |
|---|
| 506 | # so we could manage easilly the bind_perspective calls |
|---|
| 507 | |
|---|
| 508 | maintab = self.get_tab("MainTab") |
|---|
| 509 | maintab.session_notebook.connect('page-added', |
|---|
| 510 | self.__on_maintab_page_added) |
|---|
| 511 | maintab.session_notebook.connect('page-removed', |
|---|
| 512 | self.__on_maintab_page_removed) |
|---|
| 513 | |
|---|
| 514 | def connect_tabs_signals(self): |
|---|
| 515 | "Used to connect signals between tabs" |
|---|
| 516 | |
|---|
| 517 | for key, tab in self.registered_tabs.items(): |
|---|
| 518 | tab.connect_tab_signals() |
|---|
| 519 | |
|---|
| 520 | def __on_maintab_page_added(self, notebook, page, pagenum): |
|---|
| 521 | for perspective in page.perspectives: |
|---|
| 522 | try: |
|---|
| 523 | idx = PerspectiveType.types[type(perspective)] |
|---|
| 524 | |
|---|
| 525 | for callback in self.perspective_binder[idx]: |
|---|
| 526 | callback(perspective, idx, False, True) |
|---|
| 527 | except: |
|---|
| 528 | pass |
|---|
| 529 | |
|---|
| 530 | def __on_maintab_page_removed(self, notebook, page, pagenum): |
|---|
| 531 | if not isinstance(page, Session): |
|---|
| 532 | return |
|---|
| 533 | |
|---|
| 534 | for perspective in page.perspectives: |
|---|
| 535 | try: |
|---|
| 536 | idx = PerspectiveType.types[type(perspective)] |
|---|
| 537 | |
|---|
| 538 | for callback in self.perspective_binder[idx]: |
|---|
| 539 | callback(perspective, idx, True, False) |
|---|
| 540 | except: |
|---|
| 541 | pass |
|---|
| 542 | |
|---|
| 543 | def __on_toggle_tab_menu(self, menuitem, tab): |
|---|
| 544 | if menuitem.get_active(): |
|---|
| 545 | self.main_paned.add_view(tab) |
|---|
| 546 | else: |
|---|
| 547 | self.main_paned.remove_view(tab) |
|---|
| 548 | |
|---|
| 549 | def __on_routing(self, action): |
|---|
| 550 | dialog = RoutesDialog(self) |
|---|
| 551 | |
|---|
| 552 | if dialog.run() == gtk.RESPONSE_ACCEPT: |
|---|
| 553 | dialog.save() |
|---|
| 554 | |
|---|
| 555 | dialog.hide() |
|---|
| 556 | dialog.destroy() |
|---|
| 557 | |
|---|
| 558 | def __on_plugins(self, action): |
|---|
| 559 | self.plugin_window.show() |
|---|
| 560 | |
|---|
| 561 | def __on_preferences(self, action): |
|---|
| 562 | dialog = PreferenceDialog(self) |
|---|
| 563 | dialog.show() |
|---|
| 564 | |
|---|
| 565 | def __on_about(self, action): |
|---|
| 566 | dialog = gtk.AboutDialog() |
|---|
| 567 | |
|---|
| 568 | dialog.set_logo( |
|---|
| 569 | gtk.gdk.pixbuf_new_from_file(os.path.join(PIXMAPS_DIR, |
|---|
| 570 | 'pm-logo.png')) |
|---|
| 571 | ) |
|---|
| 572 | dialog.set_name("PacketManipulator") |
|---|
| 573 | dialog.set_version(PM_VERSION) |
|---|
| 574 | |
|---|
| 575 | dialog.set_website(PM_SITE) |
|---|
| 576 | dialog.set_website_label(PM_SITE) |
|---|
| 577 | |
|---|
| 578 | dialog.set_comments(_("Packet manipulation made easy%s" \ |
|---|
| 579 | "\n«Audaces fortuna adiuvat»") % \ |
|---|
| 580 | ((PM_DEVELOPMENT) and \ |
|---|
| 581 | (' (SVN revision %s)' % PM_SVN_REVISION) or \ |
|---|
| 582 | (''))) |
|---|
| 583 | |
|---|
| 584 | dialog.set_authors(['Francesco Piccinno <stack.box@gmail.com>']) |
|---|
| 585 | |
|---|
| 586 | dialog.set_copyright('\n'.join( |
|---|
| 587 | ('Copyright (C) 2008 Francesco Piccinno' \ |
|---|
| 588 | ' <stack.box at gmail dot com>', |
|---|
| 589 | 'Copyright (C) 2008 Adriano Monteiro Marques' \ |
|---|
| 590 | ' <py.adriano at gmail dot com>'))) |
|---|
| 591 | |
|---|
| 592 | dialog.set_license(_('This program is relased ' |
|---|
| 593 | 'under the terms of GPLv2')) |
|---|
| 594 | |
|---|
| 595 | dialog.run() |
|---|
| 596 | dialog.hide() |
|---|
| 597 | dialog.destroy() |
|---|
| 598 | |
|---|
| 599 | def __on_select_iface(self, action): |
|---|
| 600 | dialog = InterfaceDialog(self) |
|---|
| 601 | |
|---|
| 602 | if dialog.run() == gtk.RESPONSE_ACCEPT: |
|---|
| 603 | iface = dialog.get_selected() |
|---|
| 604 | args = dialog.get_options() |
|---|
| 605 | |
|---|
| 606 | if iface or args['capmethod'] == 1: |
|---|
| 607 | tab = self.get_tab("OperationsTab") |
|---|
| 608 | tab.tree.append_operation(SniffOperation(iface, **args)) |
|---|
| 609 | |
|---|
| 610 | dialog.hide() |
|---|
| 611 | dialog.destroy() |
|---|
| 612 | |
|---|
| 613 | def __on_new_sequence(self, action): |
|---|
| 614 | tab = self.get_tab("MainTab") |
|---|
| 615 | tab.session_notebook.create_sequence_session([]) |
|---|
| 616 | |
|---|
| 617 | def __on_open_session(self, action): |
|---|
| 618 | types = {} |
|---|
| 619 | sessions = (Backend.StaticContext, |
|---|
| 620 | Backend.SequenceContext, |
|---|
| 621 | Backend.SniffContext) |
|---|
| 622 | |
|---|
| 623 | for ctx in sessions: |
|---|
| 624 | for name, pattern in ctx.file_types: |
|---|
| 625 | types[pattern] = (name, ctx) |
|---|
| 626 | |
|---|
| 627 | dialog = gtk.FileChooserDialog(_("Select a session"), self, |
|---|
| 628 | buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, |
|---|
| 629 | gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT)) |
|---|
| 630 | |
|---|
| 631 | filterall = gtk.FileFilter() |
|---|
| 632 | filterall.set_name(_('All supported files')) |
|---|
| 633 | [filterall.add_pattern(k) for k in types] |
|---|
| 634 | dialog.add_filter(filterall) |
|---|
| 635 | |
|---|
| 636 | for pattern, (name, ctx) in types.items(): |
|---|
| 637 | filter = gtk.FileFilter() |
|---|
| 638 | filter.set_name(name) |
|---|
| 639 | filter.add_pattern(pattern) |
|---|
| 640 | dialog.add_filter(filter) |
|---|
| 641 | |
|---|
| 642 | if dialog.run() == gtk.RESPONSE_ACCEPT: |
|---|
| 643 | ctx = None |
|---|
| 644 | fname = dialog.get_filename() |
|---|
| 645 | |
|---|
| 646 | try: |
|---|
| 647 | find = fname.split('.')[-1] |
|---|
| 648 | |
|---|
| 649 | for pattern in types: |
|---|
| 650 | if pattern.split('.')[-1] == find: |
|---|
| 651 | ctx = types[pattern][1] |
|---|
| 652 | except: |
|---|
| 653 | pass |
|---|
| 654 | |
|---|
| 655 | if ctx is not Backend.SequenceContext and \ |
|---|
| 656 | ctx is not Backend.SniffContext and \ |
|---|
| 657 | ctx is not Backend.StaticContext: |
|---|
| 658 | |
|---|
| 659 | d = HIGAlertDialog(type=gtk.MESSAGE_ERROR, |
|---|
| 660 | message_format=_("Unable to open selected session"), |
|---|
| 661 | secondary_text=_("PacketManipulator is unable to guess the " |
|---|
| 662 | "file type. Try to modify the extension " |
|---|
| 663 | "and to reopen the file.")) |
|---|
| 664 | d.run() |
|---|
| 665 | d.destroy() |
|---|
| 666 | else: |
|---|
| 667 | self.open_generic_file_async(fname) |
|---|
| 668 | |
|---|
| 669 | dialog.hide() |
|---|
| 670 | dialog.destroy() |
|---|
| 671 | |
|---|
| 672 | def open_generic_file_async(self, fname): |
|---|
| 673 | """ |
|---|
| 674 | Open a generic file (pcap/sequence and other supported file format) |
|---|
| 675 | @param fname the path to the file to open |
|---|
| 676 | """ |
|---|
| 677 | tab = self.get_tab("OperationsTab") |
|---|
| 678 | tab.tree.append_operation(FileOperation(fname, FileOperation.TYPE_LOAD)) |
|---|
| 679 | |
|---|
| 680 | def open_generic_file(self, fname): |
|---|
| 681 | """ |
|---|
| 682 | Open a generic file (pcap/sequence and other supported file format) |
|---|
| 683 | @param fname the path to the file to open |
|---|
| 684 | @return a PM.Session.Base.Session object or None on errors |
|---|
| 685 | """ |
|---|
| 686 | |
|---|
| 687 | if not os.path.isfile(fname): |
|---|
| 688 | return None |
|---|
| 689 | |
|---|
| 690 | types = {} |
|---|
| 691 | sessions = (Backend.StaticContext, |
|---|
| 692 | Backend.SequenceContext, |
|---|
| 693 | Backend.SniffContext) |
|---|
| 694 | |
|---|
| 695 | for ctx in sessions: |
|---|
| 696 | for name, pattern in ctx.file_types: |
|---|
| 697 | types[pattern] = (name, ctx) |
|---|
| 698 | |
|---|
| 699 | try: |
|---|
| 700 | find = fname.split('.')[-1] |
|---|
| 701 | |
|---|
| 702 | for pattern in types: |
|---|
| 703 | if pattern.split('.')[-1] == find: |
|---|
| 704 | ctx = types[pattern][1] |
|---|
| 705 | except: |
|---|
| 706 | pass |
|---|
| 707 | |
|---|
| 708 | tab = self.get_tab("MainTab") |
|---|
| 709 | |
|---|
| 710 | if ctx is Backend.SequenceContext: |
|---|
| 711 | return tab.session_notebook.load_sequence_session(fname) |
|---|
| 712 | |
|---|
| 713 | elif ctx is Backend.SniffContext: |
|---|
| 714 | return tab.session_notebook.load_sniff_session(fname) |
|---|
| 715 | |
|---|
| 716 | elif ctx is Backend.StaticContext: |
|---|
| 717 | return tab.session_notebook.load_static_session(fname) |
|---|
| 718 | |
|---|
| 719 | def __on_save_session(self, action): |
|---|
| 720 | maintab = self.get_tab("MainTab") |
|---|
| 721 | session = maintab.get_current_session() |
|---|
| 722 | |
|---|
| 723 | if session: |
|---|
| 724 | session.save() |
|---|
| 725 | |
|---|
| 726 | def __on_save_session_as(self, action): |
|---|
| 727 | maintab = self.get_tab("MainTab") |
|---|
| 728 | session = maintab.get_current_session() |
|---|
| 729 | |
|---|
| 730 | if session: |
|---|
| 731 | session.save_as() |
|---|
| 732 | |
|---|
| 733 | def __on_quit(self, *args): |
|---|
| 734 | self.hide() |
|---|
| 735 | |
|---|
| 736 | # We need to stop the pending sniff threads |
|---|
| 737 | maintab = self.get_tab("MainTab") |
|---|
| 738 | |
|---|
| 739 | lst = [] |
|---|
| 740 | |
|---|
| 741 | for page in maintab.session_notebook: |
|---|
| 742 | if isinstance(page, Session) and \ |
|---|
| 743 | isinstance(page.context, Backend.TimedContext): |
|---|
| 744 | lst.append(page.context) |
|---|
| 745 | |
|---|
| 746 | for ctx in lst: |
|---|
| 747 | ctx.stop() |
|---|
| 748 | |
|---|
| 749 | # Avoids joining all threads are daemon |
|---|
| 750 | #for ctx in lst: |
|---|
| 751 | # ctx.join() |
|---|
| 752 | |
|---|
| 753 | log.debug("Saving options before exiting") |
|---|
| 754 | Prefs().write_options() |
|---|
| 755 | |
|---|
| 756 | gtk.main_quit() |
|---|