root/branch/max/umitGUI/ScriptManager.py @ 827

Revision 827, 14.1 kB (checked in by maxim-gavrilov, 6 years ago)

very old trunk sync

Line 
1# Copyright (C) 2007 Adriano Monteiro Marques <py.adriano@gmail.com>
2#
3# Author: Maxim Gavrilov <lovelymax@gmail.com>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19import os, os.path
20import re
21import sys
22from gtksourceview import SourceView, SourceLanguagesManager, SourceBuffer
23
24from umitCore.Paths import check_access
25from umitCore.I18N import _
26
27import gtk
28from umitGUI.FileChoosers import DirectoryChooserDialog, AllFilesFileChooserDialog
29from higwidgets.higwindows import HIGWindow
30from higwidgets.higboxes import HIGVBox, HIGHBox, HIGSpacer, hig_box_space_holder
31from higwidgets.higexpanders import HIGExpander
32from higwidgets.higlabels import HIGSectionLabel, HIGEntryLabel, HIGDialogLabel
33from higwidgets.higscrollers import HIGScrolledWindow
34from higwidgets.higtextviewers import HIGTextView
35from higwidgets.higbuttons import HIGButton
36from higwidgets.higtables import HIGTable
37from higwidgets.higdialogs import HIGAlertDialog, HIGDialog
38
39# aux alert function
40def _alert(header, text):
41    alert = HIGAlertDialog(
42        message_format='<b>%s</b>' % header,
43        secondary_text=text
44        )
45    alert.run()
46    alert.destroy()
47
48# aux nmap_fetchfile functions
49# XXX: will be moved into Paths.Search or/and into Python/Nmap wrapper
50def get_file_list(path):
51        return [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]
52
53class NmapFetch(object):
54    def __init__(self):
55        self.dirs = self.__fetchdirs()
56
57    def fetchdirs(self):
58        return self.dirs
59
60    def fetchfile(self, filename):
61        for path in self.fetchdirs():
62            fullpath = os.path.join(path, filename)
63            if check_access(fullpath, os.R_OK):
64                return fullpath
65        return None
66
67    def get_file_list(self):
68        result = []
69        for path in self.fetchdirs():
70            try:
71                for filename in get_file_list(path):
72                    fullpath = os.path.join(path, filename)
73                    if check_access(fullpath, os.R_OK):
74                        result.append(fullpath)
75            except OSError:
76                pass
77        return result
78
79    def nmap_path(self, path):
80        fullpath = os.path.abspath(path)
81        for p in self.fetchdirs():
82            if fullpath.startswith(p):
83                return fullpath[len(p)+1:] # XXX: check +1 (removing last slash) on Windows
84        return fullpath
85
86    def __fetchdirs(self):
87        # standart Nmap searching directories (see nmap.cc:nmap_fetchfile function)
88        def varpath():
89            return os.path.expandvars("${NMAPDIR}")
90        def uidpath():
91            return os.path.join(pwd.getpwuid(os.getuid()).pw_dir, ".nmap")
92        def euidpath():
93            return os.path.join(pwd.getpwuid(os.geteuid()).pw_dir, ".nmap")
94        def userpath():
95            return os.path.expanduser("~")
96        def datadirpath_win():
97            return "c:\\nmap"
98        def datadirpath():
99            return "/usr/share/nmap/"
100        def datadirpath2():
101            return "/usr/local/share/nmap/"
102        def currentpath():
103            return "."
104
105        if sys.platform != 'win32':
106            import pwd
107            checklist = [varpath, uidpath, euidpath, datadirpath, datadirpath2, currentpath]
108        else:
109            checklist = [varpath, userpath, datadirpath_win, currentpath]
110
111        paths = [os.path.abspath(f()) for f in checklist]
112        # XXX: not stable
113        return list(set(paths))
114
115class NmapFetchScripts(NmapFetch):
116    def __init__(self):
117        NmapFetch.__init__(self)
118        self.dirs = [os.path.join(d, "scripts") for d in self.dirs]
119
120    def get_file_list(self):
121        return [f for f in NmapFetch.get_file_list(self) if f.endswith(".nse")]
122
123# Model classes
124# XXX: will be moved to umitCore/
125class ScriptParseException(Exception):
126    pass
127
128class Script(object):
129    def __init__(self, path):
130        f = file(path, 'r')
131        self.data = f.read()
132        f.close()
133
134        self.path = NmapFetchScripts().nmap_path(path)
135        self.id = self._get_attr('id')
136        self.desc = self._get_attr('description')
137
138    def _get_attr(self, attr):
139        r = re.findall(attr + '\s*=\s*"([^\"]+)"', self.data)
140        # XXX: Exception vs False result - that is the Question?!
141        if not r:
142            raise ScriptParseException("Can't parse file %s" % self.path)
143        res = r[0]
144        res = res.replace('\\', ' ')
145        res = res.replace('\n', ' ')
146        res = res.strip()
147        return res
148
149    # for set-element support
150    def __eq__(self, other):
151        return self.path.__eq__(other.path)
152
153    def __hash__(self):
154        return self.path.__hash__()
155
156class ScriptSelection(object):
157    def __init__(self, selected = ""):
158        self.d = dict([(s, False) for s in script_manager])
159        self.set_selected(selected)
160
161    def set_selected(self, selected):
162        for filename in selected.split(";"):
163            script = script_manager.find_by_path(filename)
164            if self.d.has_key(script):
165                self.d[script] = True
166
167    def get_selected(self):
168        return ";".join([script.path for script in self.d.keys() if self.d[script]])
169
170    def is_selected(self, script):
171        return self.d.get(script, False)
172
173    def select(self, script):
174        self.d[script] = True
175
176    def unselect(self, script):
177        self.d[script] = False
178
179class ScriptManager(set):
180    def __init__(self):
181        for filename in NmapFetchScripts().get_file_list():
182            try:
183                self.add_file(filename)
184            except ScriptParseException:
185                pass
186
187    def add_file(self, filename):
188        script = Script(filename)
189        self.add(script)
190
191    def add_dir(self, dirname):
192        res = False
193        for name in get_file_list(dirname):
194            if name.endswith('.nse'):
195                try:
196                    self.add_file(os.path.join(dirname, name))
197                    res = True
198                except ScriptParseException:
199                    pass
200        return res
201
202    def find_by_path(self, filename):
203        for s in self:
204            if s.path == filename:
205                return s
206        return None
207
208# Singletone
209script_manager = ScriptManager()
210
211# GUI classes
212class ScriptManagerWindow(HIGWindow):
213    def __init__(self):
214        HIGWindow.__init__(self)
215        self.set_title(_("Script Manager"))
216        self.set_position(gtk.WIN_POS_CENTER)
217        self.create_widgets()
218        self.update_model()
219
220    def create_list(self):
221        scroll = HIGScrolledWindow()
222        scroll.set_shadow_type(gtk.SHADOW_IN)
223        self.model = gtk.ListStore(object, str)
224        self.list_view = gtk.TreeView(self.model)
225        scroll.add(self.list_view)
226
227        self.model.set_sort_column_id(1, gtk.SORT_ASCENDING)
228        self.list_view.set_headers_visible(False)
229        cell = gtk.CellRendererText()
230        col = gtk.TreeViewColumn('id', cell, text=1)
231        self.list_view.append_column(col)
232        self.list_view.set_search_column(1)
233        self.list_view.connect('cursor-changed', self.id_select_cb)
234        return scroll
235
236    def create_text(self):
237        scroll = HIGScrolledWindow()
238        scroll.set_shadow_type(gtk.SHADOW_IN)
239        self.text_buffer = SourceBuffer()
240        self.text_buffer.set_highlight(True)
241        lang = SourceLanguagesManager().get_language_from_mime_type('text/x-lua')
242        self.text_buffer.set_language(lang)
243        text_view = SourceView(self.text_buffer)
244        text_view.set_editable(True)
245        text_view.set_auto_indent(True)
246        scroll.add(text_view)
247        return scroll
248
249    def create_buttons(self):
250        hbox = HIGHBox()
251        btn_add_file = HIGButton(_("Add file"), stock=gtk.STOCK_OPEN)
252        btn_add_dir = HIGButton(_("Add dir"), stock=gtk.STOCK_DIRECTORY)
253        btn_delete = HIGButton(stock=gtk.STOCK_DELETE)
254        btn_close = HIGButton(stock=gtk.STOCK_CLOSE)
255        hbox.pack_start(btn_add_file)
256        hbox.pack_start(btn_add_dir)
257        hbox.pack_start(btn_delete)
258        hbox.pack_start(btn_close)
259        hbox.set_border_width(5)
260        hbox.set_spacing(6)
261        btn_add_file.connect('clicked', self.add_file_cb)
262        btn_add_dir.connect('clicked', self.add_dir_cb)
263        btn_delete.connect('clicked', self.delete_cur_cb)
264        btn_close.connect('clicked', lambda x,y=None:self.destroy())
265        return hbox
266
267    def create_widgets(self):
268        self.set_size_request(600, 400)
269        hpane = gtk.HPaned()
270        hpane.pack1(self.create_list(), False)
271        hpane.pack2(self.create_text(), True)
272        #hbox = HIGHBox()
273        #hbox.pack_start(self.create_list())
274        #hbox.pack_start(self.create_text())
275        main_vbox = HIGVBox()
276        main_vbox.pack_start(hpane, True, True)
277        main_vbox.pack_start(self.create_buttons(), False, False)
278        self.add(main_vbox)
279
280    def update_model(self):
281        self.model.clear()
282        for script in script_manager:
283            self.model.append((script, script.id))
284
285    def id_select_cb(self, list_view):
286        (model, it) = list_view.get_selection().get_selected()
287        if it:
288            script = model[it][0]
289            self.text_buffer.set_text(script.data)
290
291    def add_file_cb(self, widget):
292        file_chooser = AllFilesFileChooserDialog(_("Select Script"))
293        file_chooser.run()
294        name = file_chooser.get_filename()
295        file_chooser.destroy()
296        if name:
297            self.add_file(name)
298
299    def add_dir_cb(self, widget):
300        file_chooser = DirectoryChooserDialog(_("Select Scripts Directory"))
301        file_chooser.run()
302        dirname = file_chooser.get_filename()
303        file_chooser.destroy()
304        if dirname:
305            self.add_dir(dirname)
306
307    def delete_cur_cb(self, widget):
308        (model, it) = self.list_view.get_selection().get_selected()
309        if it:
310            cur = model.get_path(it)[0]
311            script_manager.remove(model[it][0])
312            model.remove(it)
313            self.list_view.get_selection().select_path((cur,))
314            self.id_select_cb(self.list_view)
315
316    def add_file(self, filename):
317        if check_access(filename, os.R_OK):
318            try:
319                script_manager.add_file(filename)
320                self.update_model()
321            except:
322                _alert(
323                    _('File is not a NSE script file'),
324                    _("Selected file is not a NSE script file. Umit can not \
325parse this file. Please, select another."))
326        else:
327            _alert(
328                _('Can not open selected file'),
329                _("Umit can not open selected file. Please, select another."))
330
331    def add_dir(self, dirname):
332        if script_manager.add_dir(dirname):
333            self.update_model()
334        else:
335            _alert(
336                _('Can not find any NSE script files in the directory'),
337                _("Umit can not find any NSE script files in the selected \
338directory. Please, select another."))
339
340class ScriptChooserDialog(HIGDialog):
341    def __init__(self, selected = ""):
342        HIGDialog.__init__(self, _("Select Necessory Scripts"), None,
343                           gtk.DIALOG_MODAL,
344                           (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
345                            gtk.STOCK_OK, gtk.RESPONSE_OK))
346        self.selection = ScriptSelection(selected)
347        self.set_size_request(400, 400)
348        self.create_widgets()
349        self.update_model()
350
351    def create_list(self):
352        scroll = HIGScrolledWindow()
353        scroll.set_shadow_type(gtk.SHADOW_IN)
354        self.model = gtk.ListStore(object, bool, str)
355        self.list_view = gtk.TreeView(self.model)
356        scroll.add(self.list_view)
357
358        self.model.set_sort_column_id(2, gtk.SORT_ASCENDING)
359        self.list_view.set_headers_visible(False)
360        self.list_view.set_search_column(2)
361
362        cell = gtk.CellRendererToggle()
363        cell.connect('toggled', self.toggled_cb, self.model)
364        col = gtk.TreeViewColumn('b', cell, active=1)
365        self.list_view.append_column(col)
366
367        cell = gtk.CellRendererText()
368        col = gtk.TreeViewColumn('id', cell, text=2)
369        self.list_view.append_column(col)
370
371        self.list_view.connect('cursor-changed', self.id_select_cb)
372        return scroll
373
374    def create_text(self):
375        scroll = HIGScrolledWindow()
376        scroll.set_shadow_type(gtk.SHADOW_IN)
377        text_view = HIGTextView()
378        text_view.set_editable(False)
379        scroll.add(text_view)
380        self.text_buffer = text_view.get_buffer()
381        return scroll
382
383    def create_widgets(self):
384        vpane = gtk.VPaned()
385        vpane.pack1(self.create_list(), True)
386        vpane.pack2(self.create_text(), False)
387        self.vbox.add(vpane)
388        self.show_all()
389
390    def update_model(self):
391        self.model.clear()
392        for script in script_manager:
393            self.model.append((
394                script,
395                self.selection.is_selected(script),
396                script.id))
397
398    def id_select_cb(self, list_view):
399        (model, it) = list_view.get_selection().get_selected()
400        if it:
401            script = model[it][0]
402            self.text_buffer.set_text(script.desc)
403
404    def toggled_cb(self, cell, path, model):
405        model[path][1] = not model[path][1]
406        if model[path][1]:
407            self.selection.select(model[path][0])
408        else:
409            self.selection.unselect(model[path][0])
410
411    def get_scripts(self):
412        return self.selection.get_selected()
413
414if __name__ == "__main__":
415    sm = ScriptManagerWindow()
416    sm.show_all()
417    sm.connect("destroy", gtk.main_quit)
418    gtk.main()
419
420    #sd = ScriptChooserDialog("")
421    #if sd.run() == gtk.RESPONSE_OK:
422    #    print "OK:", sd.get_scripts()
423    #else:
424    #    print "Cancel"
425    #sd.destroy()
Note: See TracBrowser for help on using the browser.