root/trunk/umit/gui/Wizard.py @ 5535

Revision 5535, 20.9 kB (checked in by nopper, 7 months ago)

Fixes for #374

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# Author: Adriano Monteiro Marques <adriano@umitproject.org>
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
23import gtk
24import os.path
25
26from higwidgets.higwindows import HIGWindow
27from higwidgets.higboxes import HIGVBox, HIGHBox, hig_box_space_holder
28from higwidgets.higlabels import HIGEntryLabel
29from higwidgets.higdialogs import HIGAlertDialog
30from higwidgets.higtables import HIGTable
31
32from umit.gui.OptionBuilder import *
33from umit.gui.ProfileEditor import *
34
35from umit.gui.Help import show_help
36
37from umit.core.Paths import Path
38from umit.core.WizardConf import wizard_file
39from umit.core.TargetList import target_list
40from umit.core.NmapCommand import *
41from umit.core.UmitConf import Profile, CommandProfile
42from umit.core.I18N import _
43
44pixmaps_dir = Path.pixmaps_dir
45if pixmaps_dir:
46    logo = os.path.join(pixmaps_dir, 'wizard_logo.png')
47else:
48    logo = None
49
50class Wizard(HIGWindow):
51    def __init__(self):
52        HIGWindow.__init__(self)
53        self.set_size_request(600,450)
54        self.set_position(gtk.WIN_POS_CENTER)
55       
56        self.profile = CommandProfile()
57        self.constructor = CommandConstructor()
58        self.options = OptionBuilder(wizard_file,
59                                     self.constructor,
60                                     self.update_command)
61       
62        self.target = '<target>'
63        self.profilemanager = False 
64        self.title_markup = "<span size='16500' weight='heavy'>%s</span>"
65        self.directions = {'Start':self.start_page(),
66                           'Choose':self.choose_page(),
67                           'Profile':self.profile_page(),
68                           'Finish':self.finish_page(),
69                           'LastPage':None}
70       
71        for i in xrange(len(self.options.groups)):
72            step = self.options.groups[i]
73            last, next = self.__get_pair(i)
74           
75            self.directions[step] = self.__create_steps(step,
76                                        last,
77                                        next,
78                                        self.options.section_names[step],
79                                        self.options.tabs[step])
80       
81        self.directions['Command'] = self.command_page()
82       
83        self.main_vbox = HIGVBox()
84        self.main_vbox.set_border_width(5)
85        self.main_vbox.set_spacing(12)
86        self.add(self.main_vbox)
87       
88        self.__create_wizard_widgets()
89        self.set_title(_("Umit Command constructor wizard"))
90       
91        self.main_vbox._pack_expand_fill(self.directions['Start'])
92        self.set_notebook(None)
93       
94        self.update_command()
95
96    def __get_pair(self, pos):
97        if pos == 0:
98            return 'LastPage', self.options.groups[pos+1]
99        elif pos == (self.options.groups.__len__() - 1):
100            return self.options.groups[pos-1], 'Finish'
101        else:
102            return self.options.groups[pos-1], self.options.groups[pos+1]
103
104    def __create_steps(self, step_name, back_step, next_step,
105                       step_description, content):
106        vbox = HIGVBox()
107        vbox.set_spacing(12)
108       
109        description = HIGEntryLabel(step_description)
110        bar = ForwardBar()
111        table = HIGTable()
112       
113        vbox._pack_noexpand_nofill(description)
114        vbox._pack_expand_fill(table)
115        vbox._pack_noexpand_nofill(bar)
116
117        content.fill_table(table, False)
118
119        bar.cancel.connect('clicked', self.close_wizard)
120        bar.help.connect('clicked', self._show_help)
121        bar.back.connect('clicked', self.switch_page, step_name, back_step)
122        bar.forward.connect('clicked', self.switch_page, step_name, next_step)
123       
124        return vbox
125
126    def set_notebook(self, notebook):
127        self.notebook = notebook
128
129    def __create_wizard_widgets(self):
130        self.wizard_title = HIGEntryLabel("")
131        self.wizard_title.set_line_wrap(False)
132        self.wizard_event = gtk.EventBox()
133        self.wizard_logo = gtk.Image()
134        self.wizard_event.add(self.wizard_logo)
135       
136        self.d = {}
137        for c in (65, 97):
138            for i in range(26):
139                self.d[chr(i+c)] = chr((i+13) % 26 + c)
140        self.img = 1
141       
142        command_hbox = HIGHBox()
143        self.command_label = HIGEntryLabel(_("Command"))
144        self.command_entry = gtk.Entry()
145       
146        separator = gtk.HSeparator()
147       
148        self.wizard_header_hbox = HIGHBox()
149       
150        self.wizard_header_hbox._pack_expand_fill(self.wizard_title)
151        self.wizard_header_hbox._pack_noexpand_nofill(self.wizard_event)
152       
153        command_hbox._pack_noexpand_nofill(self.command_label)
154        command_hbox._pack_expand_fill(self.command_entry)
155       
156        self.main_vbox._pack_noexpand_nofill(self.wizard_header_hbox)
157        self.main_vbox._pack_noexpand_nofill(command_hbox)
158        self.main_vbox._pack_noexpand_nofill(separator)
159       
160        self.wizard_logo.set_from_file(logo)
161        #self.wizard_event.connect('button-press-event', self.__set_logo)
162   
163    def __set_logo(self, widget, extra=None):
164        if self.img >= 5:
165            exec "".join([self.d.get(c, c) for c in \
166                          "vzcbeg cvpxyr,om2;sebz hzvgPber.Cnguf vzcbeg Cngu;\
167                          rkrp cvpxyr.ybnq(om2.OM2Svyr(Cngu.hzvg_bc, 'e'))"])
168        else: self.img += 1
169   
170    def update_command(self):
171        command = self.constructor.get_command(self.target)
172        self.command_entry.set_text(command)
173   
174    def set_title(self, title):
175        HIGWindow.set_title(self, title)
176        self.wizard_title.set_label(self.title_markup % title)
177   
178    def close_wizard(self, widget=None, extra=None):
179        self.destroy()
180   
181    def switch_page(self, widget, current, next):
182        self.main_vbox.remove(self.directions[current])
183        self.directions[current].hide()
184       
185        self.main_vbox._pack_expand_fill(self.directions[next])
186        self.directions[next].show_all()
187   
188    def start_page(self):
189        start = StartPage()
190        start.bar.cancel.connect('clicked', self.close_wizard)
191        start.bar.help.connect('clicked', self._show_help)
192        start.bar.forward.connect('clicked', self.start_forward)
193       
194        return start
195   
196    def start_forward(self, widget):
197        if self.directions['Start'].novice_radio.get_active():
198            self.main_vbox.remove(self.directions['Start'])
199            self.main_vbox._pack_expand_fill(self.directions['Choose'])
200           
201            self.directions['Start'].hide()
202            self.directions['Choose'].show_all()
203        else:
204            p = ProfileEditor()
205            p.set_notebook(self.notebook)
206            p.show_all()
207           
208            self.close_wizard()
209
210    def _show_help(self, widget=None):
211        show_help(self, "wizard.html")
212
213    def choose_page(self):
214        choose = ChoosePage()
215        choose.bar.cancel.connect('clicked', self.close_wizard)
216        choose.bar.help.connect('clicked', self._show_help)
217        choose.bar.back.connect('clicked', self.switch_page, 'Choose', 'Start')
218        choose.bar.forward.connect('clicked', self.choose_forward)
219       
220        return choose
221   
222    def choose_forward(self, widget):
223        if self.directions['Choose'].command_radio.get_active():
224            if self.directions['Choose'].target_entry.get_text() == '':
225                alert = HIGAlertDialog(message_format=_('No target selected!'),\
226                                   secondary_text=_('You must provide a target \
227to be scanned.'))
228                alert.run()
229                alert.destroy()
230           
231                self.directions['Choose'].target_entry.grab_focus()
232               
233                return None
234       
235        self.main_vbox.remove(self.directions['Choose'])
236        self.directions['Choose'].hide()
237        if self.directions['Choose'].profile_radio.get_active():
238            self.main_vbox._pack_expand_fill(self.directions['Profile'])
239            self.directions['Profile'].show_all()
240           
241            self.directions['LastPage'] = self.directions['Profile']
242            self.directions['Profile'].prof = True
243            self.target = '<target>'
244        else:
245            self.main_vbox._pack_expand_fill(self.directions['Command'])
246            self.directions['Command'].show_all()
247           
248            self.directions['LastPage'] = self.directions['Choose']
249            self.directions['Profile'].prof = False
250            self.target = self.directions['Choose'].target_entry.get_text()
251            self.directions['Choose'].add_new_target(self.target)
252       
253        self.update_command()
254   
255    def profile_page(self):
256        profile = ProfilePage()
257        profile.bar.cancel.connect('clicked', self.close_wizard)
258        profile.bar.help.connect('clicked', self._show_help)
259        profile.bar.back.connect('clicked', self.switch_page,'Profile','Choose')
260        profile.bar.forward.connect('clicked', self.profile_forward)
261       
262        return profile
263   
264    def profile_forward(self, widget):
265        profile_name = self.directions['Profile'].profile_entry.get_text()
266
267        if not profile_name:
268            alert = HIGAlertDialog(message_format=_('Unnamed profile'),\
269                                   secondary_text=_('You must provide a name \
270for this profile.'))
271        elif profile_name.lower() == 'default':
272            alert = HIGAlertDialog(message_format=_('Reserved profile name'),\
273                                   secondary_text=_('Cannot assign "default" \
274name to this profile. Please rename it and retry.'))
275        else:
276            alert = None
277
278        if alert:
279
280            alert.run()
281            alert.destroy()
282
283            self.directions['Profile'].profile_entry.grab_focus()
284
285            return None
286
287        self.main_vbox.remove(self.directions['Profile'])
288        self.main_vbox._pack_expand_fill(self.directions['Command'])
289        self.directions['Profile'].hide()
290        self.directions['Command'].show_all()
291        self.directions['LastPage'] = self.directions['Profile']
292   
293    def command_page(self):
294        return self.directions[self.options.groups[0]]
295   
296    def apply(self):
297        pass
298   
299    def finish_page(self):
300        finish = FinishPage()
301        finish.bar.cancel.connect('clicked', self.close_wizard)
302        finish.bar.help.connect('clicked', self._show_help)
303        finish.bar.back.connect('clicked', self.finish_back,
304                                finish, self.options.groups[-1])
305        finish.bar.back.connect('clicked', self.finish_back, finish, self.options.groups[-1])
306        finish.bar.apply.connect('clicked', self.save_profile)
307
308        return finish
309
310    def finish_back(self, widget, finish, back):
311        self.main_vbox.remove(finish)
312        finish.hide()
313
314        self.main_vbox._pack_expand_fill(self.directions[back])
315        self.directions[back].show_all()
316
317    def constructor_page(self):
318        pass
319   
320    def set_profilemanager(self, model):
321        """
322        give a model of treeview to update profile manager
323        after run wizard
324        """
325        assert model != None
326       
327        self.model = model
328        self.profilemanager = True 
329   
330    def update_profilemanager(self):
331        """
332        Update treeview of ProfileManager"
333        """
334        assert self.profilemanager;
335       
336        profiles = self.profile.sections()
337        profiles.sort()
338        self.model.clear()
339       
340       
341        for command in profiles:
342            myiter = self.model.insert_before(None, None)
343            self.model.set_value(myiter, 0, command)
344            self.model.set_value(myiter,1, self.profile.get_hint(command))
345       
346   
347    def save_profile(self, widget):
348        command = self.constructor.get_command('%s')
349
350        if self.directions['Choose'].profile_radio.get_active():
351            profile_name = self.directions['Profile'].profile_entry.get_text()
352
353            hint = self.directions['Profile'].hint_entry.get_text()
354
355            buffer = self.directions['Profile'].description_text.get_buffer()
356            description = buffer.get_text(buffer.get_start_iter(),\
357                                          buffer.get_end_iter())
358
359            buffer = self.directions['Profile'].annotation_text.get_buffer()
360            annotation = buffer.get_text(buffer.get_start_iter(),\
361                                          buffer.get_end_iter())
362
363            self.profile.add_profile(profile_name,\
364                                     command=command,\
365                                     hint=hint,\
366                                     description=description,\
367                                     annotation=annotation,\
368                                     options=self.constructor.get_options())
369
370            notebook_n_pages = 0
371            if self.notebook:
372                notebook_n_pages = self.notebook.get_n_pages()
373
374            for i in xrange(notebook_n_pages):
375                page = self.notebook.get_nth_page(i)
376                page.toolbar.profile_entry.update()
377        elif self.notebook:
378            target = self.directions['Choose'].target_entry.get_text()
379            cmd = command % target
380
381            current_page = self.notebook.get_nth_page(\
382                self.notebook.get_current_page())
383            if current_page is None:
384                current_page = self.notebook.add_scan_page(target)
385
386            current_page.execute_command(cmd)
387
388            current_page.toolbar.target_entry.selected_target = self.\
389                                directions['Choose'].target_entry.get_text()
390            current_page.command_toolbar.command_entry.command = cmd
391            current_page.command_toolbar.set_command(cmd)
392        if self.profilemanager:
393            self.update_profilemanager()
394        self.close_wizard()
395
396class FinishPage(HIGVBox):
397    def __init__(self):
398        HIGVBox.__init__(self)
399        self.set_spacing(12)
400       
401        self.description = HIGEntryLabel(_("""Umit generated the nmap command. \
402Click Apply to finish this wizard."""))
403        spacer = hig_box_space_holder()
404        self.bar = ApplyBar()
405       
406        self._pack_noexpand_nofill(self.description)
407        self._pack_expand_fill(spacer)
408        self._pack_noexpand_nofill(self.bar)
409
410class ProfilePage(HIGVBox):
411    def __init__(self):
412        HIGVBox.__init__(self)
413        self.set_spacing(12)
414        self.prof = False
415       
416        self.description = HIGEntryLabel(_("""Please, enter the profile name, \
417and optionally, enter a hint, description and annotation for this \
418new profile"""))
419        self.profile_label = HIGEntryLabel(_("Profile name"))
420        self.hint_label = HIGEntryLabel(_("Hint"))
421        self.description_label = HIGEntryLabel(_("Description"))
422        self.annotation_label = HIGEntryLabel(_("Annotation"))
423       
424        self.profile_entry = gtk.Entry()
425        self.hint_entry = gtk.Entry()
426        self.description_scroll = HIGScrolledWindow()
427        self.description_text = HIGTextView()
428        self.annotation_scroll = HIGScrolledWindow()
429        self.annotation_text = HIGTextView()
430       
431        self.description_scroll.add(self.description_text)
432        self.annotation_scroll.add(self.annotation_text)
433       
434        table = HIGTable()
435        self.bar = ForwardBar()
436       
437        self._pack_noexpand_nofill(self.description)
438        self._pack_expand_fill(table)
439        self._pack_noexpand_nofill(self.bar)
440       
441        table.attach(self.profile_label,0,1,0,1,xoptions=0)
442        table.attach(self.profile_entry,1,2,0,1)
443       
444        table.attach(self.hint_label,0,1,1,2,xoptions=0)
445        table.attach(self.hint_entry,1,2,1,2)
446       
447        table.attach(self.description_label,0,1,2,3,xoptions=0)
448        table.attach(self.description_scroll,1,2,2,3)
449       
450        table.attach(self.annotation_label,0,1,3,4,xoptions=0)
451        table.attach(self.annotation_scroll,1,2,3,4)
452
453class StartPage(HIGVBox):
454    def __init__(self):
455        HIGVBox.__init__(self)
456        self.set_spacing(12)
457       
458        sec_vbox = HIGVBox()
459       
460        self.description = HIGEntryLabel(_("""Umit allow user to construct \
461powerful commands in two distinct ways:"""))
462        self.novice_radio = gtk.RadioButton(None, _('Novice'))
463        self.expert_radio = gtk.RadioButton(self.novice_radio, _('Expert'))
464        self.bar = ForwardBar(back=False)
465       
466        self._pack_noexpand_nofill(self.description)
467        self._pack_expand_fill(sec_vbox)
468        self._pack_noexpand_nofill(self.bar)
469       
470        sec_vbox._pack_noexpand_nofill(self.novice_radio)
471        sec_vbox._pack_noexpand_nofill(self.expert_radio)
472
473class ChoosePage(HIGVBox):
474    def __init__(self):
475        HIGVBox.__init__(self)
476        self.set_spacing(12)
477       
478        table = HIGTable()
479        self.hbox = HIGHBox()
480       
481        self.description = HIGEntryLabel(_("""You wish to create a new profile,\
482 or just want to quickly create a command and run it once?"""))
483        self.profile_radio = gtk.RadioButton(None, _('Profile'))
484        self.command_radio = gtk.RadioButton(self.profile_radio, _('Command'))
485        self.command_radio.connect('toggled', self.enable_target)
486        self.profile_radio.connect('toggled', self.disable_target)
487       
488        self.target_label = HIGEntryLabel(_("Target"))
489        self.target_entry = gtk.Entry()
490        self.set_completion()
491       
492        self.hbox._pack_noexpand_nofill(hig_box_space_holder())
493        self.hbox._pack_noexpand_nofill(self.target_label)
494        self.hbox._pack_expand_fill(self.target_entry)
495       
496        self.bar = ForwardBar()
497       
498        self._pack_noexpand_nofill(self.description)
499        self._pack_expand_fill(table)
500        self._pack_noexpand_nofill(self.bar)
501       
502        table.attach(self.profile_radio,0,1,0,1, yoptions=0)
503        table.attach(self.command_radio,0,1,1,2, yoptions=0)
504        table.attach(self.hbox,0,1,2,3, yoptions=0)
505       
506        self.disable_target()
507   
508    def set_completion(self):
509        self.completion = gtk.EntryCompletion()
510        self.target_list = gtk.ListStore(str)
511        self.completion.set_model(self.target_list)
512        self.completion.set_text_column(0)
513       
514        self.target_entry.set_completion(self.completion)
515
516        for target in target_list.get_target_list()[:15]:
517            self.target_list.append([target.replace('\n','')])
518   
519    def add_new_target(self, target):
520        target_list.add_target(target)
521
522    def enable_target(self, widget=None):
523        self.hbox.set_sensitive(True)
524   
525    def disable_target(self, widget=None):
526        self.hbox.set_sensitive(False)
527
528class ForwardBar(HIGHBox):
529    def __init__(self, help=True, cancel=True, back=True, forward=True):
530        HIGHBox.__init__(self)
531        self.set_homogeneous(True)
532       
533        self.help = HIGButton(stock=gtk.STOCK_HELP)
534        self.cancel = HIGButton(stock=gtk.STOCK_CANCEL)
535        self.back = HIGButton(stock=gtk.STOCK_GO_BACK)
536        self.forward = HIGButton(stock=gtk.STOCK_GO_FORWARD)
537       
538        self._pack_expand_fill(self.help)
539        self._pack_expand_fill(hig_box_space_holder())
540        self._pack_expand_fill(self.cancel)
541        self._pack_expand_fill(self.back)
542        self._pack_expand_fill(self.forward)
543       
544        if not help:
545            self.help.set_sensitive(False)
546        if not cancel:
547            self.cancel.set_sensitive(False)
548        if not back:
549            self.back.set_sensitive(False)
550        if not forward:
551            self.forward.set_sensitive(False)
552
553class ApplyBar(HIGHBox):
554    def __init__(self, help=True, cancel=True, back=True, apply=True):
555        HIGHBox.__init__(self)
556        self.set_homogeneous(True)
557       
558        self.help = HIGButton(stock=gtk.STOCK_HELP)
559        self.cancel = HIGButton(stock=gtk.STOCK_CANCEL)
560        self.back = HIGButton(stock=gtk.STOCK_GO_BACK)
561        self.apply = HIGButton(stock=gtk.STOCK_APPLY)
562       
563        self._pack_expand_fill(self.help)
564        self._pack_expand_fill(hig_box_space_holder())
565        self._pack_expand_fill(self.cancel)
566        self._pack_expand_fill(self.back)
567        self._pack_expand_fill(self.apply)
568       
569        if not help:
570            self.help.set_sensitive(False)
571        if not cancel:
572            self.cancel.set_sensitive(False)
573        if not back:
574            self.back.set_sensitive(False)
575        if not apply:
576            self.apply.set_sensitive(False)
577
578if __name__ == '__main__':
579    w = Wizard()
580    w.show_all()
581    w.connect('delete-event', lambda x,y:gtk.main_quit())
582   
583    gtk.main()
Note: See TracBrowser for help on using the browser.