root/trunk/umit/gui/MainWindow.py @ 4789

Revision 4789, 44.0 kB (checked in by luis, 4 years ago)

Fixed #317. Now to show help documentation, it use a function from umit.gui.Help -> show_help. All calls outside wizard getting same error was fixed.

Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Copyright (C) 2005-2006 Insecure.Com LLC.
5# Copyright (C) 2007-2008 Adriano Monteiro Marques
6#
7# Authors: Adriano Monteiro Marques <adriano@umitproject.org>
8#          Cleber Rodrigues <cleber.gnu@gmail.com>
9#          Francesco Piccinno <stack.box@gmail.com>
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation; either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; if not, write to the Free Software
23# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24
25import os
26import gtk
27import sys
28from os.path import split, isfile, join
29import xml.sax.saxutils
30
31from types import StringTypes
32from time import time
33from tempfile import mktemp
34
35from higwidgets.higwindows import HIGMainWindow
36from higwidgets.higdialogs import HIGDialog, HIGAlertDialog
37from higwidgets.higlabels import HIGEntryLabel
38from higwidgets.higboxes import HIGHBox, HIGVBox
39
40from umit.gui.FileChoosers import ResultsFileChooserDialog
41from umit.gui.FileChoosers import SaveResultsFileChooserDialog
42from umit.gui.ScanNotebook import ScanNotebook, ScanNotebookPage
43from umit.gui.ProfileEditor import ProfileEditor
44from umit.gui.ProfileManager import ProfileManager
45from umit.gui.Wizard import Wizard
46from umit.gui.ProfileManager import ProfileManager
47from umit.gui.About import About
48from umit.gui.DiffCompare import DiffWindow
49from umit.gui.SearchWindow import SearchWindow
50from umit.gui.BugReport import BugReport
51from umit.gui.SchedulerControl import SchedControl
52from umit.gui.SchedulerEdit import SchedSchemaEditor
53from umit.gui.SMTPSetup import SMTPSetup
54
55from umit.interfaceeditor.Main import InterfaceEditor
56
57from umit.gui.Help import show_help
58
59from umit.core.Paths import Path
60from umit.core.RecentScans import recent_scans
61from umit.core.UmitLogging import log
62from umit.core.I18N import _
63from umit.core.UmitOptionParser import option_parser
64from umit.core.UmitConf import SearchConfig
65from umit.core.UmitDB import Scans, UmitDB
66from umit.core.Utils import amiroot, is_maemo
67from umit.core.DataDecay import remove_old_data
68import umit.core.Scheduler as Scheduler
69
70from umit.db.XMLStore import XMLStore
71from umit.inventory.Viewer import InventoryViewer
72
73from umit.plugin.Window import PluginWindow
74from umit.plugin.Engine import PluginEngine
75
76root = amiroot()
77UmitMainWindow = None
78hildon = None
79
80if is_maemo():
81    import hildon
82    class UmitMainWindow(hildon.Window):
83        def __init__(self):
84            hildon.Window.__init__(self)
85            self.set_resizable(False)
86            self.set_border_width(0)
87            self.vbox = gtk.VBox()
88            self.vbox.set_border_width(0)
89            self.vbox.set_spacing(0)
90
91else:
92    class UmitMainWindow(HIGMainWindow):
93        def __init__(self):
94            HIGMainWindow.__init__(self)
95            self.vbox = gtk.VBox()
96
97            screen = self.get_screen()
98            if screen.get_width() >= 800 and screen.get_height() >= 600:
99                self.set_default_size(760, 570) # (800 - 40, 600 - 30)
100
101class MainWindow(UmitMainWindow):
102    def __init__(self):
103        UmitMainWindow.__init__(self)
104        self.set_title(_("Umit"))
105
106        self._plugin_win = PluginWindow()
107        self._icontheme = gtk.IconTheme()
108        self.main_accel_group = gtk.AccelGroup()
109
110        self.add_accel_group(self.main_accel_group)
111
112        self.add(self.vbox)
113
114        self.connect('delete-event', self._exit_cb)
115
116        self.schedctrl = SchedControl(None)
117        self._create_ui_manager()
118        self._create_menubar()
119        self._create_toolbar()
120        self._create_scan_notebook()
121        self._verify_root()
122
123        self.running_ni = False
124
125        # These dialogs should be instanciated on demand
126        # Unfortunately, due to a GTK bug on the filefilters (or our own
127        # stupidity), we are creating/destroying them at each callback
128        # invocation. sigh.
129        self._profile_filechooser_dialog = None
130        self._results_filechooser_dialog = None
131
132        self._prepare_first_scan()
133
134        # Loading files passed as argument
135        files = option_parser.get_open_results()
136        if len(files) >= 1:
137            for file in files:
138                self._load(filename=file)
139
140    def configure_focus_chain(self):
141        self.vbox.set_focus_chain()
142
143    def _verify_root(self):
144        if not root:
145            non_root = NonRootWarning()
146           
147    def _get_running_ni(self):
148        """
149        Return True if there is a Network Inventory open.
150        """
151        return self.__niwin
152   
153    def _set_running_ni(self, running):
154        """
155        Set to True if Network Inventory is running, otherwise, False.
156        """
157        self.__niwin = running
158
159    def _create_ui_manager(self):
160        self.ui_manager = gtk.UIManager()
161
162        # See info on ActionGroup at:
163        # * http://www.pygtk.org/pygtk2reference/class-gtkactiongroup.html
164        # * http://www.gtk.org/api/2.6/gtk/GtkActionGroup.html
165        self.main_action_group = gtk.ActionGroup('MainActionGroup')
166
167        # See info on Action at:
168        # * http://www.pygtk.org/pygtk2reference/class-gtkaction.html
169        # * http://www.gtk.org/api/2.6/gtk/GtkAction.html
170
171        # Each action tuple can go from 1 to six fields, example:
172        # ('Open Scan Results',      -> Name of the action
173        #   gtk.STOCK_OPEN,          ->
174        #   _('_Open Scan Results'), ->
175        #   None,
176        #   _('Open the results of a previous scan'),
177        #   lambda x: True)
178
179        about_icon = None
180        try: about_icon = gtk.STOCK_ABOUT
181        except: pass
182
183        self.main_actions = [ \
184            # Top level
185            ('Scan', None, _('Sc_an'), None), 
186
187            ('Wizard',
188             gtk.STOCK_CONVERT,
189             _('_Command Wizard'),
190             '<Control>i',
191             _('Open nmap command constructor wizard'),
192             self._wizard_cb),
193
194             ('Save Scan',
195              gtk.STOCK_SAVE,
196              _('_Save Scan'),
197              None,
198              _('Save current scan results'),
199              self._save_scan_results_cb),
200
201              ('Open Scan',
202               gtk.STOCK_OPEN,
203               _('_Open Scan'),
204               None,
205               _('Open the results of a previous scan'),
206               self._load_scan_results_cb),
207
208
209               ('Tools', None, _('_Tools'), None), 
210
211               ('New Scan',
212                gtk.STOCK_NEW,
213                _('_New Scan'),
214                "<Control>T",
215                _('Create a new Scan Tab'),
216                self._new_scan_cb),
217
218                ('Close Scan',
219                 gtk.STOCK_CLOSE,
220                 _('Close Scan'),
221                 "<Control>w",
222                 _('Close current scan tab'),
223                 self._close_scan_cb),
224
225                 ('New Profile',
226                  gtk.STOCK_JUSTIFY_LEFT,
227                  _('New _Profile'),
228                  '<Control>p',
229                  _('Create a new scan profile'),
230                  self._new_scan_profile_cb),
231
232                  ('Search Scan',
233                   gtk.STOCK_FIND,
234                   _('Search Scan Results'),
235                   '<Control>f',
236                   _('Search for a scan result'),
237                   self._search_scan_result),
238
239                   ('Edit Profile',
240                    gtk.STOCK_PROPERTIES,
241                    _('_Edit Selected Profile'),
242                    '',
243                    _('Edit selected scan profile'),
244                    self._edit_scan_profile_cb),
245
246                    ('Delete Profile', 
247                     gtk.STOCK_PROPERTIES, 
248                     _('_Delete Selected Profile'), 
249                     '', 
250                     _('Delete selected scan profile'), 
251                     self._delete_scan_profile_cb), 
252                   
253                    ('Profile Manager',
254                     gtk.STOCK_DND_MULTIPLE,
255                     _('Profile Manager'),
256                     '<Control>m',
257                     _('Use to manage profiles'),
258                     self._profile_manager),           
259                   
260                    ('Interface Editor',
261                     gtk.STOCK_DND_MULTIPLE,
262                     _('Interface Editor'),
263                     '<Control>n',
264                     _('Use to edit profile/wizard'),
265                     self._uie),   
266
267                     ('New Profile with Selected',
268                      gtk.STOCK_PROPERTIES,
269                      _('New P_rofile with Selected'),
270                      '<Control>r',
271                      _('Use the selected scan profile to create another'),
272                      self._new_scan_profile_with_selected_cb),
273                     
274                      ('Extensions',
275                       gtk.STOCK_INFO,
276                       _('_Extensions'),
277                       '<Control>e',
278                       _('Extensions manager'),
279                       self._show_plugin_manager),
280
281                      ('Quit',
282                       gtk.STOCK_QUIT,
283                       _('_Quit'),
284                       None,
285                       _('Quit this application'),
286                       self._exit_cb),
287
288
289                       # Top Level
290                       ('Profile', None, _('_Profile'), None),
291
292                       ('Compare Results',
293                        gtk.STOCK_DND_MULTIPLE,
294                        _('Compare Results'),
295                        "<Control>D",
296                        _('Compare Scan Results using Diffies'),
297                        self._load_diff_compare_cb),
298
299            # Network Inventory
300            ('Inventory', None, _('_Inventory'), None),
301
302            ('Add Scan Inv', 
303                gtk.STOCK_ADD,
304                _('_Add scan to Inventory'), None,
305                _("Add finished scan on current tab to Network Inventory"),
306                self._add_scan_inv
307            ),
308
309            ('Open Inv',
310                None,
311                _('Network _Inventory'),
312                "<Shift><Control>I",
313                _("Run Network Inventory"),
314                self._open_inv
315            ),
316
317            # Scan Scheduler
318            ('Scheduler', None, _('_Scheduler'), None),
319           
320            ('Sched Control', self.schedctrl.stock_icon,
321             self.schedctrl.status_text,
322             None, self.schedctrl.status_text,
323             self.schedctrl._scheduler_control),
324           
325            ('Sched Editor', None, _('_Editor'),
326             None, _("Open Scheduler Editor"),
327             self._open_schededit),
328           
329            # SMTP Setup
330            ('SMTP Setup', None, _("SMTP Setup"),
331             None, _("Open SMTP Accounts editor"),
332             self._open_smtpsetup),
333
334                        # Top Level
335                        ('Help', None, _('_Help'), None),
336
337                        ('Report a bug',
338                         gtk.STOCK_DIALOG_INFO,
339                         _('_Report a bug'),
340                         '<Control>b',
341                         _("Report a bug"),
342                         self._show_bug_report
343                         ),
344
345                         ('About',
346                          about_icon,
347                          _('_About'),
348                          '<Control>a',
349                          _("About Umit"),
350                          self._show_about_cb
351                          ),
352
353                          ('Show Help',
354                           gtk.STOCK_HELP,
355                           _('_Help'),
356                           None,
357                           _('Shows the application help'),
358                           self._show_help),
359                       ]
360
361        # See info on UIManager at:
362        # * http://www.pygtk.org/pygtk2reference/class-gtkuimanager.html       
363        # * http://www.gtk.org/api/2.6/gtk/GtkUIManager.html
364
365        # UIManager supports UI "merging" and "unmerging". So, suppose there's
366        # no scan running or scan results opened, we should have a minimal
367        # interface. When we one scan running, we should "merge" the scan UI.
368        # When we get multiple tabs opened, we might merge the tab UI.
369
370        # This is the default, minimal UI
371
372        self.default_ui = """<menubar>
373            <menu action='Scan'>
374            <menuitem action='New Scan'/>
375            <menuitem action='Close Scan'/>
376            <menuitem action='Save Scan'/>
377            <menuitem action='Open Scan'/>
378            <placeholder name='RecentScans'>
379            </placeholder>
380            <menuitem action='Quit'/>
381            </menu>
382
383            <menu action='Tools'>
384            <menuitem action='Wizard'/>
385            <menuitem action='Compare Results'/>
386            <menuitem action='Search Scan'/>
387            <separator/>
388            <menuitem action='Extensions'/>
389            <menuitem action='SMTP Setup'/>
390            <menu action='Scheduler'>
391                <menuitem action='Sched Editor' />
392                <menuitem action='Sched Control' />
393            </menu>
394            <menu action='Inventory'>
395                <menuitem action='Add Scan Inv'/>
396                <menuitem action='Open Inv'/>
397            </menu>
398            </menu>
399
400            <menu action='Profile'>
401            <menuitem action='New Profile'/>
402            <menuitem action='New Profile with Selected'/>
403            <menuitem action='Edit Profile'/>
404            <menuitem action='Delete Profile'/>
405            <separator/>
406            <menuitem action='Profile Manager'/>
407            <menuitem action='Interface Editor'/>
408            </menu>
409
410            <menu action='Help'>
411            <menuitem action='Show Help'/>
412            <menuitem action='Report a bug'/>
413            <menuitem action='About'/>
414            </menu>
415
416            </menubar>
417
418            <toolbar>
419            <toolitem action='New Scan'/>
420            <toolitem action='Wizard'/>
421            <toolitem action='Save Scan'/>
422            <toolitem action='Open Scan'/>
423            <separator/>
424            <toolitem action='Sched Control'/>
425            <separator/>
426            <toolitem action='Report a bug'/>
427            <toolitem action='Show Help'/>
428            </toolbar>
429            """
430
431        self.main_action_group.add_actions(self.main_actions)
432
433        for action in self.main_action_group.list_actions():
434            action.set_accel_group(self.main_accel_group)
435            action.connect_accelerator()
436
437        self.ui_manager.insert_action_group(self.main_action_group, 0)
438        self.ui_manager.add_ui_from_string(self.default_ui)
439
440        self._rscans_actiongroup = gtk.ActionGroup('UIRecentScans')
441        self.ui_manager.insert_action_group(self._rscans_actiongroup, 1)
442        self._rscans_merge_id = 0
443        self.update_recent_scans()
444
445        self.schedctrl.ui_action = self.main_action_group.get_action(
446                'Sched Control')
447
448    def _open_schededit(self, action):
449        """
450        Open Scheduler Schemas Editor.
451        """
452        win = SchedSchemaEditor()
453        win.show_all()
454
455    def _open_smtpsetup(self, action):
456        """
457        Open SMTP Accounts Editor.
458        """
459        win = SMTPSetup()
460        win.show_all()
461       
462    def _open_inv(self, action):
463        """
464        Open Inventories visualizer.
465        """
466        if self.running_ni:
467            return
468       
469        self.niwin = InventoryViewer(self)
470        self.niwin.show_all()
471        self.running_ni = True
472
473    def _add_scan_inv(self, action):
474        """
475        Add scan to inventory.
476        """
477        current_page = self.scan_notebook.get_nth_page(self.scan_notebook.get_current_page())
478
479        try:
480            status = current_page.status
481        except:
482            alert = HIGAlertDialog(message_format=_("No scan tab"),
483                    secondary_text=_("There is no scan tab or scan result "
484                        "being shown. Run a scan and then retry adding."))
485            alert.run()
486            alert.destroy()
487            return None
488       
489        if status.get_status() in [ "scan_failed", "unknown", "empty",
490                                    "scanning", "parsing_result" ]:
491
492            run_something_text = _("You tried adding a scan to the Inventory, "
493                    "but there isn't a finished scan on the active tab!")
494
495            dlg = HIGAlertDialog(self, message_format=_("No scan tab"),
496                                 secondary_text=run_something_text)
497            dlg.run()
498            dlg.destroy()
499            return None
500
501        # if we got to this point, it should be possible to add this scan
502        inventory_title = self.scan_notebook.get_tab_title(current_page)
503
504        xml_scanfile = mktemp()
505        f = open(xml_scanfile, "w")
506        current_page.parsed.write_xml(f)
507        f.close()
508
509        log.debug("Adding scan to inventory database..")
510
511        xmlstore = XMLStore(Path.umitdb_ng, False)
512        try:
513            xmlstore.store(xml_scanfile, current_page.parsed, inventory_title)
514        finally:
515            # close connection to the inventory's database
516            xmlstore.close()
517        os.remove(xml_scanfile)
518        log.debug("Insertion finished")
519
520        dlg = HIGAlertDialog(self,
521                message_format=_('Insertion finished!'),
522                secondary_text=(
523                    _("Scan has been added to the") +
524                    " %r " % inventory_title +
525                    _("inventory.")))
526        dlg.run()
527        dlg.destroy()
528       
529        if self.running_ni: # update inventory viewer
530            self.niwin._update_viewer()
531           
532    def _show_bug_report(self, widget):
533        bug = BugReport()
534        bug.show_all()
535
536    def _search_scan_result(self, widget):
537        search_window = SearchWindow(self._load_search_result,
538                                     self.scan_notebook)
539        search_window.show_all()
540
541    def _load_search_result(self, results):
542        for result in results:
543            if results[result][1].is_unsaved():
544                for i in range(self.scan_notebook.get_n_pages()):
545                    if results[result][0] == "Unsaved " + \
546                       self.scan_notebook.get_nth_page(i).get_tab_label():
547                        self.scan_notebook.set_current_page(i)
548            else:
549                page = self._load(parsed_result=results[result][1],
550                                  title=results[result][1].scan_name)
551                page.status.set_search_loaded()
552   
553    def _show_plugin_manager(self, widget, data=None):
554        self._plugin_win.show()
555   
556    def _close_scan_cb(self, widget, data=None):
557        # data can be none, if the current page is to be closed
558        if data is None:
559            page_num = self.scan_notebook.get_current_page()
560        # but can also be this page's content, which will be used
561        # to find this page number
562        else:
563            page_num = self.scan_notebook.page_num(data)
564        page = self.scan_notebook.get_nth_page(page_num)
565        filename = None
566
567        if page is None or not isinstance(page, ScanNotebookPage):
568            return True
569
570        if page.status.unsaved_unchanged \
571           or page.status.unsaved_changed\
572           or page.status.loaded_changed:
573
574            log.debug("Found changes on closing tab")
575            dialog = HIGDialog(buttons=(gtk.STOCK_SAVE, gtk.RESPONSE_OK,
576                                        _('Close anyway'), gtk.RESPONSE_CLOSE,
577                                        gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
578
579            title = self.scan_notebook.get_tab_title(page)
580
581            alert = None
582            if title:
583                alert = HIGEntryLabel('<b>%s "%s"</b>' % (_("Save changes on"),
584                                                          title))
585            else:
586                alert = HIGEntryLabel('<b>%s</b>' % _("Save changes"))
587
588            text = HIGEntryLabel(_('The given scan has unsaved changes.\n\
589What do you want to do?'))
590            hbox = HIGHBox()
591            hbox.set_border_width(5)
592            hbox.set_spacing(12)
593
594            vbox = HIGVBox()
595            vbox.set_border_width(5)
596            vbox.set_spacing(12)
597
598            image = gtk.Image()
599            image.set_from_stock(gtk.STOCK_DIALOG_QUESTION,gtk.ICON_SIZE_DIALOG)
600
601            vbox.pack_start(alert)
602            vbox.pack_start(text)
603            hbox.pack_start(image)
604            hbox.pack_start(vbox)
605
606            dialog.vbox.pack_start(hbox)
607            dialog.vbox.show_all()
608
609            response = dialog.run()
610            dialog.destroy()
611
612            if response == gtk.RESPONSE_OK:
613                filename = self._save_scan_results_cb(page)
614                # filename = None means that user didn't saved the result
615            elif response == gtk.RESPONSE_CANCEL:
616                return False
617
618            self.store_result(page, filename)
619
620        elif page.status.scanning:
621            log.debug("Trying to close a tab with a running scan")
622            dialog = HIGDialog(buttons=(_('Close anyway'), gtk.RESPONSE_CLOSE,
623                                        gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
624
625            title = self.scan_notebook.get_tab_title(page)
626
627            alert = None
628            if title:
629                alert = HIGEntryLabel('<b>%s "%s"</b>' % (_("Trying to close"),
630                                                          title))
631            else:
632                alert = HIGEntryLabel('<b>%s</b>' % _("Trying to close"))
633
634            text = HIGEntryLabel(_('The page you are trying to close has \
635a scan running at the background.\nWhat do you want to do?'))
636            hbox = HIGHBox()
637            hbox.set_border_width(5)
638            hbox.set_spacing(12)
639
640            vbox = HIGVBox()
641            vbox.set_border_width(5)
642            vbox.set_spacing(12)
643
644            image = gtk.Image()
645            image.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG)
646
647            vbox.pack_start(alert)
648            vbox.pack_start(text)
649            hbox.pack_start(image)
650            hbox.pack_start(vbox)
651
652            dialog.vbox.pack_start(hbox)
653            dialog.vbox.show_all()
654
655            response = dialog.run()
656            dialog.destroy()
657
658            if response == gtk.RESPONSE_CLOSE:
659                page.kill_scan()
660            elif response == gtk.RESPONSE_CANCEL:
661                return False
662        elif not page.status.empty:
663            alert = HIGAlertDialog(message_format=_('Closing current Scan Tab'),
664                                   secondary_text=_('Are you sure you want \
665to close current Scan Tab?'),
666          buttons=gtk.BUTTONS_OK_CANCEL,
667          type=gtk.MESSAGE_WARNING)
668            response = alert.run()
669            alert.destroy()
670
671            if response != gtk.RESPONSE_OK:
672                return False
673
674        page.close_tab()
675        # Close (and maybe remove) temporary files.
676        try:
677            page.command_execution.close()
678        except AttributeError:
679            # Page didn't have a scan.
680            pass
681
682        self.scan_notebook.remove_page(page_num)
683        return True
684
685    def store_result(self, page, filename):
686        page.parsed.scan_name = self.scan_notebook.get_tab_title(page)
687
688        if not filename:
689            filename = mktemp()
690            f = open(filename, "w")
691            page.parsed.write_xml(f)
692            f.close()
693
694        search_config = SearchConfig()
695        if search_config.store_results:
696            try:
697                log.debug(">>> Saving result into data base...")
698                scan = Scans(scan_name=self.scan_notebook.get_tab_title(page),
699                             nmap_xml_output=open(filename).read(),
700                             date=time())
701            except:
702                log.debug("Error while trying to store result in Data Base!")
703
704        # Remove temp file created, if possible.
705        try:
706            os.remove(filename)
707        except OSError, err:
708            # See umit.core.NmapCommand.close
709            if getattr(err, 'winerror', None) != 32:
710                raise
711
712    def update_recent_scans(self):
713        """Shows the most recent saved scans in the 'Scan' menu."""
714        # clean previous recent scans listing, if any
715        if self._rscans_merge_id:
716            for action in self._rscans_actiongroup.list_actions():
717                self._rscans_actiongroup.remove_action(action)
718            self.ui_manager.remove_ui(self._rscans_merge_id)
719            # ensure_update is used here so we can be sure that the
720            # UIManager updates our UI. Not doing so will cause
721            # new items in the recent scans listing to appear at the
722            # end of the current listing.
723            self.ui_manager.ensure_update()
724
725        r_scans = recent_scans.get_recent_scans_list()
726        rscans_ui = """
727        <menubar>
728            <menu action='Scan'>
729                <placeholder name='RecentScans'>
730                %s
731                </placeholder>
732            </menu>
733        </menubar>"""
734        new_rscan_xml = ''
735
736        actions = []
737
738        # Add the seven most recent saved scans to the menu.
739        for scan in r_scans[:7]:
740            scan = scan.replace('\n', '')
741            if os.access(split(scan)[0], os.R_OK) and isfile(scan):
742                scan = scan.replace('\n', '')
743                new_rscan = (scan,
744                             None,
745                             scan,
746                             None,
747                             scan,
748                             self._load_recent_scan)
749                new_rscan_xml += "<menuitem action='%s'/>\n" % \
750                              xml.sax.saxutils.escape(scan)
751                actions.append(new_rscan)
752        new_rscan_xml += "<separator />\n"
753
754        self._rscans_actiongroup.add_actions(actions)
755        self._rscans_merge_id = self.ui_manager.add_ui_from_string(
756                rscans_ui % new_rscan_xml)
757
758    def _create_menubar(self):
759        # Get and pack the menubar
760        menubar = self.ui_manager.get_widget('/menubar')
761
762        if is_maemo():
763            menu = gtk.Menu()
764            for child in menubar.get_children():
765                child.reparent(menu)
766            self.set_menu(menu)
767            menubar.destroy()
768            self.menubar = menu
769        else:
770            self.menubar = menubar
771            self.vbox.pack_start(self.menubar, False, False, 0)
772
773        self.menubar.show_all()
774
775    def _create_toolbar(self):
776        toolbar = self.ui_manager.get_widget('/toolbar')
777
778        if is_maemo():
779            tb = gtk.Toolbar()
780            for child in toolbar.get_children():
781                child.reparent(tb)
782            self.add_toolbar(tb)
783            self.toolbar = tb
784            toolbar.destroy()
785        else:
786            self.toolbar = toolbar
787            self.vbox.pack_start(self.toolbar, False, False, 0)
788
789        self.toolbar.show_all()
790
791    def _title_edited_cb(self, widget, old_text, new_text, page):
792        # Called when the user try to edit the title
793        # we could decide to set or not the title
794
795        # Only loaded and unsaved tab can change their title
796        # so let's filter
797
798        status = page.status
799
800        # Change to unsaved. (needs adds?)
801        if status.loaded_unchanged or status.loaded_changed:
802            page.status.set_loaded_changed()
803        elif status.unsaved_unchanged or status.unsaved_changed or status.empty:
804            page.status.set_unsaved_changed()
805        else:
806            # No compatible status.
807            return False
808
809        log.debug(">>> Changing scan_name")
810        page.parsed.set_scan_name(new_text)
811
812        # Ok we can change this title.
813        return True
814
815    def _create_scan_notebook(self):
816        self.scan_notebook = ScanNotebook()
817        self.scan_notebook.close_scan_cb = self._close_scan_cb
818        self.scan_notebook.title_edited_cb = self._title_edited_cb
819       
820        if is_maemo():
821            # No padding. We need space!
822            self.vbox.pack_start(self.scan_notebook, True, True, 0)
823        else:
824            self.vbox.pack_start(self.scan_notebook, True, True, 4)
825
826        # Conencting ScanNotebook Callbacks
827        self.scan_notebook.connect("page-removed", self._update_when_removed)
828        self.scan_notebook.connect("page-added", self._update_when_added)
829   
830    def _prepare_first_scan(self):
831        # Load here becouse some plugins require some signals
832        # Set the mainwindow and load the selected plugins
833        PluginEngine().core.mainwindow = self
834        PluginEngine().load_selected_plugins()
835
836        page = self._new_scan_cb()
837        self.scan_notebook.show_all()
838
839        # Applying some command line options
840        target = option_parser.get_target()
841        profile = option_parser.get_profile()
842        nmap = option_parser.get_nmap()
843
844        if target:
845            page.toolbar.selected_target = target
846        if profile:
847            page.toolbar.selected_profile = profile
848
849        if target and profile:
850            log.debug(">>> Executing scan with the given args: %s \
851                      with %s" % (target, profile))
852            page.toolbar.scan_button.set_sensitive(True)
853            page.start_scan_cb()
854
855        elif target and nmap:
856            page.command_toolbar.command = " ".join(["".join(nmap),target])
857            page.toolbar.scan_button.set_sensitive(True)
858            page.start_scan_cb()
859
860        elif not target and nmap:
861            #non_valid_target = NonValidTarget()
862            #del non_valid_target
863            page.command_toolbar.command = "nmap " + " ".join(nmap)
864            page.toolbar.scan_button.set_sensitive(True)
865            page.start_scan_cb()
866
867    def _update_when_removed(self, notebook, child, pagenum):
868        self._update_main_menu()
869
870    def _update_when_added(self, notebook, child, pagenum):
871        self._update_main_menu()
872
873    def _update_main_menu(self):
874        page = self.scan_notebook.get_n_pages()
875
876        # Get some menu widgets
877        close_scan = self.ui_manager.get_action("/menubar/Scan/Close Scan")
878        save_scan = self.ui_manager.get_action("/menubar/Scan/Save Scan")
879        compare_results = self.ui_manager.\
880                        get_action("/menubar/Tools/Compare Results")
881        new_profile_with_selected = self.ui_manager.\
882                        get_action("/menubar/Profile/New Profile with Selected")
883        edit_profile = self.ui_manager.\
884                     get_action("/menubar/Profile/Edit Profile")
885
886        if page == 0:
887            close_scan.set_sensitive(False)
888            save_scan.set_sensitive(False)
889            compare_results.set_sensitive(False)
890            new_profile_with_selected.set_sensitive(False)
891            edit_profile.set_sensitive(False)
892        else:
893            close_scan.set_sensitive(True)
894            save_scan.set_sensitive(True)
895            compare_results.set_sensitive(True)
896            new_profile_with_selected.set_sensitive(True)
897            edit_profile.set_sensitive(True)
898
899    def _create_statusbar(self):
900        self.statusbar = gtk.Statusbar()
901        self.vbox.pack_start(self.statusbar, False, False, 0)
902
903    def _wizard_cb(self, widget):
904        w = Wizard()
905        w.set_notebook(self.scan_notebook)
906
907        w.show_all()
908
909    def _load_scan_results_cb(self, p):
910        self._results_filechooser_dialog = ResultsFileChooserDialog(\
911            title=p.get_name())
912
913        if (self._results_filechooser_dialog.run() == gtk.RESPONSE_OK):
914            self._load(filename=self._results_filechooser_dialog.get_filename())
915
916        self._results_filechooser_dialog.destroy()
917        self._results_filechooser_dialog = None
918
919    def _load_recent_scan(self, widget):
920        self._load(widget.get_name())
921
922    def _verify_page_usage(self, page):
923        """Verifies if given page is empty and can be used to load a result, or
924        if it's not empty and shouldn't be used to load a result. Returns True,
925        if it's ok to be used, and False if it's not.
926        """
927        if page is None \
928           or page.status.saved\
929           or page.status.unsaved_unchanged\
930           or page.status.unsaved_changed\
931           or page.status.loaded_unchanged\
932           or page.status.loaded_changed\
933           or page.status.parsing_result\
934           or page.status.scanning\
935           or page.status.search_loaded:
936            return False
937        else:
938            return True
939
940    def _load(self, filename=None, parsed_result=None, title=None):
941        scan_page = None
942
943        if filename or parsed_result:
944            current_page = self.scan_notebook.\
945                         get_nth_page(self.scan_notebook.get_current_page())
946
947            if self._verify_page_usage(current_page):
948                log.debug(">>> Loading inside current scan page.")
949                scan_page = current_page
950            else:
951                log.debug(">>> Creating a new page to load it.")
952                scan_page = self._new_scan_cb()
953
954            log.debug(">>> Enabling page widgets")
955            scan_page.enable_widgets()
956
957        if filename and os.access(filename, os.R_OK):
958            # Load scan result from file
959            log.debug(">>> Loading file: %s" % filename)
960            log.debug(">>> Permissions to access file? %s" % os.access(filename,
961                                                                       os.R_OK))
962
963            # Parse result
964            f = open(filename)
965            scan_page.parse_result(f)
966            scan_page.saved_filename = filename
967
968            # Closing file to avoid problems with file descriptors
969            f.close()
970
971            log.debug(">>> Setting tab label")
972            self.scan_notebook.set_tab_title(scan_page, title)
973
974        elif parsed_result:
975            # Load scan result from parsed object
976            scan_page.load_from_parsed_result(parsed_result)
977
978            log.debug(">>> Setting tab label")
979            self.scan_notebook.set_tab_title(scan_page, None)
980
981        elif filename and not os.access(filename, os.R_OK):
982            alert = HIGAlertDialog(message_format=_('Permission denied'),
983                                   secondary_text=_('Don\'t have read access \
984to the path'))
985            alert.run()
986            alert.destroy()
987            return 
988        else:
989            alert = HIGAlertDialog(message_format=_('Could not load result'),
990                                   secondary_text=_('An unidentified error \
991occouried and the scan result was unable to be loaded properly.'))
992            alert.run()
993            alert.destroy()
994            return 
995
996        log.debug(">>> Setting flag that defines that there is no changes at \
997this scan result yet")
998        scan_page.changes = False
999        scan_page.status.set_loaded_unchanged()
1000
1001        log.debug(">>> Showing loaded result page")
1002        self.scan_notebook.set_current_page(self.scan_notebook.get_n_pages()-1)
1003        return scan_page
1004
1005    def _save_scan_results_cb(self, saving_page):
1006        current_page = self.scan_notebook.get_nth_page(self.scan_notebook.\
1007                                                       get_current_page())
1008
1009        try:
1010            status = current_page.status
1011        except:
1012            alert = HIGAlertDialog(message_format=_('No scan tab'),
1013                                   secondary_text=_('There is no scan tab or \
1014scan result been shown. Run a scan and then try to save it.'))
1015            alert.run()
1016            alert.destroy()
1017            return None
1018
1019
1020        log.debug(">>> Page status: %s" % current_page.status.status)
1021
1022        if status.empty or status.unknown:    # EMPTY or UNKNOWN
1023            # Show a dialog saying that there is nothing to be saved
1024            alert = HIGAlertDialog(message_format=_('Nothing to save'),
1025                                   secondary_text=_('No scan on this tab. \
1026Start a scan an then try again'))
1027            alert.run()
1028            alert.destroy()
1029
1030        elif status.scan_failed:
1031            alert = HIGAlertDialog(message_format=_('Nothing to save'),
1032                                   secondary_text=_('The scan has failed! \
1033There is nothing to be saved.'))
1034            alert.run()
1035            alert.destroy()
1036
1037        elif status.parsing_result:    # PARSING_RESULT
1038            # Say that the result is been parsed
1039            alert = HIGAlertDialog(message_format=_('Parsing the result'),
1040                                   secondary_text=_('The result is still \
1041been parsed. You can not save the result yet.'))
1042            alert.run()
1043            alert.destroy()
1044
1045        elif status.scanning:    # SCANNING
1046            # Say that the scan is still running
1047            alert = HIGAlertDialog(message_format=_('Scan is running'),
1048                                   secondary_text=_('The scan process is not \
1049finished yet. Wait until the scan is finished and then try to save it again.'))
1050            alert.run()
1051            alert.destroy()
1052
1053        elif status.unsaved_unchanged or status.unsaved_changed or \
1054             status.search_loaded:
1055            # UNSAVED_UNCHANGED and UNSAVED_CHANGED
1056            # Show the dialog to choose the path to save scan result
1057            self._save_results_filechooser_dialog = SaveResultsFileChooserDialog(\
1058                title=_('Save Scan'))   
1059            response = self._save_results_filechooser_dialog.run()
1060
1061            filename = None
1062            if (response == gtk.RESPONSE_OK):
1063                filename = self._save_results_filechooser_dialog.get_filename()
1064                # add .usr to filename if there is no other extension
1065                if filename.find('.') == -1:
1066                    filename += ".usr"
1067                self._save(current_page, filename)
1068
1069            self._save_results_filechooser_dialog.destroy()
1070            self._save_results_filechooser_dialog = None
1071
1072            return filename
1073
1074        elif status.loaded_changed:    # LOADED_CHANGED
1075            # Save the current result at the loaded file
1076            self._save(current_page, current_page.saved_filename)
1077        elif status.saved or status.loaded_unchanged:
1078            pass
1079        else:    # UNDEFINED status
1080            alert = HIGAlertDialog(message_format=_('Nothing to save'),
1081                                   secondary_text=_('No scan on this tab. \
1082Start a scan an then try again'))
1083            alert.run()
1084            alert.destroy()
1085
1086    def _show_about_cb(self, widget):
1087        a = About()
1088        a.show_all()
1089
1090    def _save(self, saving_page, saved_filename):
1091        log.debug(">>> File been saved: %s" % saved_filename)
1092        if os.access(split(saved_filename)[0], os.W_OK):
1093            f = None
1094            try:
1095                f = open(saved_filename, 'w')
1096            except:
1097                alert = HIGAlertDialog(message_format=_('Can\'t save file'),
1098                                       secondary_text=_('Can\'t open file \
1099to write'))
1100                alert.run()
1101                alert.destroy()
1102            else:
1103                saving_page.saved = True
1104                saving_page.changes = False
1105                saving_page.saved_filename = saved_filename
1106                saving_page.collect_umit_info()
1107
1108                log.debug(">>> Page saved? %s" % saving_page.status.saved)
1109                log.debug(">>> Changes on page? %s" % saving_page.status.status)
1110                log.debug(">>> File to be saved at: %s" % \
1111                          saving_page.saved_filename)
1112
1113                saving_page.parsed.write_xml(f)
1114
1115                # Closing file to avoid problems with file descriptors
1116                f.close()
1117
1118                # Setting page status to saved
1119                saving_page.status.set_saved()
1120
1121                # Saving recent scan information
1122                recent_scans.add_recent_scan(saved_filename)
1123                recent_scans.save()
1124                self.update_recent_scans()
1125
1126        else:
1127            alert = HIGAlertDialog(message_format=_('Permission denied'),
1128                                   secondary_text=_('Don\'t have write \
1129access to this path.'))
1130            alert.run()
1131            alert.destroy()
1132
1133    def _new_scan_cb(self, widget=None, data=None):
1134        """Append a new ScanNotebookPage to ScanNotebook
1135        New tab properties:
1136        - Empty
1137        - Disabled widgets
1138        - Ready to start a new scan
1139        - Untitled scan
1140        """
1141        return self.scan_notebook.add_scan_page(data)
1142        ## Integration UIE
1143        # Put focus at the target combo, so user can open umit and start writing the target
1144        # page.target_focus()
1145
1146        # return page
1147       
1148    def _uie(self, p):
1149        uie = InterfaceEditor()
1150        uie.show_all()
1151    def _profile_manager(self,p):
1152        pm = ProfileManager()
1153        pm.show_all()
1154    def _profile_manager(self,p):
1155        """ Show Profile Manager """
1156        pm = ProfileManager()
1157        pm.set_notebook(self.scan_notebook)
1158        pm.show_all()
1159   
1160    def _new_scan_profile_cb(self, p):
1161        pe = ProfileEditor()
1162        pe.set_notebook(self.scan_notebook)
1163
1164        pe.show_all()
1165
1166    def _edit_scan_profile_cb(self, p):
1167        page = self.scan_notebook.get_nth_page\
1168             (self.scan_notebook.get_current_page())
1169        if page is None:
1170            return
1171
1172        profile = page.toolbar.selected_profile
1173       
1174       
1175
1176        pe = ProfileEditor(profile)
1177        pe.set_notebook(self.scan_notebook)
1178
1179        pe.show_all()
1180
1181    def _delete_scan_profile_cb(self, p): 
1182        page = self.scan_notebook.get_nth_page\
1183             (self.scan_notebook.get_current_page())
1184
1185        if page is None:
1186            return
1187
1188        profile = page.toolbar.selected_profile
1189
1190        pe = ProfileEditor(profile)
1191        pe.set_notebook(self.scan_notebook)
1192        pe.on_delete()
1193
1194    def _new_scan_profile_with_selected_cb(self, p):
1195        page = self.scan_notebook.get_nth_page(\
1196            self.scan_notebook.get_current_page())
1197
1198        if page is None:
1199            return
1200
1201        profile = page.toolbar.selected_profile
1202
1203        pe = ProfileEditor(profile)
1204        pe.clean_profile_info()
1205        pe.set_notebook(self.scan_notebook)
1206
1207        pe.show_all()
1208
1209    def _alert_with_action_name_cb(self, p):
1210        d = HIGAlertDialog(parent=self,
1211                           message_format=p.get_name(),
1212                           secondary_text=_("The text above is this \
1213action's name"))
1214        d.run()
1215        d.destroy()
1216
1217    def _show_help(self, action):
1218        show_help(self, "index.html")
1219       
1220    def _exit_cb (self, widget=None, extra=None):
1221        for page in self.scan_notebook.get_children():
1222            if not self._close_scan_cb(page):
1223                self.show_all()
1224                return True
1225        else:
1226            # Cleaning up data base
1227            UmitDB().cleanup(SearchConfig().converted_save_time)
1228
1229            # Saving the plugins
1230            PluginEngine().plugins.save_changes()
1231
1232            # Remove old data from database
1233            remove_old_data()
1234
1235            gtk.main_quit()
1236
1237    def _load_diff_compare_cb (self, widget=None, extra=None):
1238        # We must change this test dict
1239        # This dict has the following sintax:
1240        # key = Scan name
1241        # value = nmap output in string format
1242        dic = {}
1243
1244        for i in range(self.scan_notebook.get_n_pages()):
1245            page = self.scan_notebook.get_nth_page(i)
1246            scan_name = self.scan_notebook.get_tab_title(page)
1247
1248            if not scan_name:
1249                scan_name = _("Scan ") + str(i+1)
1250
1251            dic[scan_name] = page.parsed
1252
1253        self.diff_window = DiffWindow(dic)
1254
1255        self.diff_window.show_all()
1256
1257
1258    # Properties
1259    running_ni = property(_get_running_ni, _set_running_ni)
1260
1261
1262class NonRootWarning(HIGAlertDialog):
1263    def __init__(self):
1264        warning_text = _('''You are trying to run Umit with a non-root user!\n
1265Some nmap options need root privileges to work.''')
1266
1267        HIGAlertDialog.__init__(self, message_format=_('Non root user'),
1268                                secondary_text=warning_text)
1269
1270        self.run()
1271        self.destroy()
1272
1273class NonValidTarget (HIGAlertDialog):
1274    """ Alert for bad nmap option"""
1275    def __init__(self):
1276        warning_text = _('''You run the umit with nmap option and didn't \
1277specified a valid target (see the umit options)''')
1278
1279        HIGAlertDialog.__init__(self, message_format=_('Non valid target'),
1280                                secondary_text=warning_text)
1281
1282        self.run()
1283        self.destroy()
1284
1285
1286if __name__ == '__main__':
1287    w = MainWindow()
1288    w.show_all()
1289    gtk.main()
Note: See TracBrowser for help on using the browser.