1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-09 14:11:29 +00:00

Apply PEP 8 style guidance to zenmap

Using the pep8 tool (https://pypi.python.org/pypi/pep8), fixed the
following style issues:

Count   Issue
11      E201 whitespace after '['
8       E203 whitespace before ','
41      E211 whitespace before '('
11      E221 multiple spaces before operator
61      E225 missing whitespace around operator
237     E231 missing whitespace after ':'
91      E251 no spaces around keyword / parameter equals
19      E261 at least two spaces before inline comment
41      E301 expected 1 blank line, found 0
200     E302 expected 2 blank lines, found 1
356     E303 too many blank lines (2)
563     E501 line too long (106 characters)
39      E701 multiple statements on one line (colon)
13      E702 multiple statements on one line (semicolon)
4       W291 trailing whitespace
2       W293 blank line contains whitespace
8       W391 blank line at end of file
21      W601 .has_key() is deprecated, use 'in'
2       W602 deprecated form of raising exception

The remaining issues are long lines due to very deep data structures. I
chose not to alter them, as it would involve backslash-continuation
where whitespace is not permitted:

./zenmapGUI/ScanInterface.py:323:80: E501 line too long (90 characters)
./zenmapGUI/ScanInterface.py:456:80: E501 line too long (84 characters)
./zenmapGUI/ScanInterface.py:464:80: E501 line too long (84 characters)
./zenmapGUI/ScanInterface.py:472:80: E501 line too long (122 characters)
./zenmapGUI/ScanInterface.py:479:80: E501 line too long (122 characters)
./zenmapGUI/ScanInterface.py:920:80: E501 line too long (94 characters)
./zenmapGUI/ScanInterface.py:923:80: E501 line too long (93 characters)
./zenmapGUI/MainWindow.py:575:80: E501 line too long (99 characters)
./zenmapGUI/MainWindow.py:906:80: E501 line too long (99 characters)
This commit is contained in:
dmiller
2014-01-08 19:50:22 +00:00
parent 9210a7f1fa
commit 5c662fffdc
100 changed files with 2287 additions and 1814 deletions

View File

@@ -119,4 +119,4 @@
# * *
# ***************************************************************************/
__all__ = ["bestwidgets", "core", "gui", "util"];
__all__ = ["bestwidgets", "core", "gui", "util"]

View File

@@ -122,7 +122,6 @@
import gtk
class BWBox(gtk.Box):
"""
"""
@@ -131,38 +130,32 @@ class BWBox(gtk.Box):
"""
self.pack_start(widget, True, True, padding)
def bw_pack_start_expand_nofill(self, widget, padding=0):
"""
"""
self.pack_start(widget, True, False, padding)
def bw_pack_start_noexpand_nofill(self, widget, padding=0):
"""
"""
self.pack_start(widget, False, False, padding)
def bw_pack_end_expand_fill(self, widget, padding=0):
"""
"""
self.pack_end(widget, True, True, padding)
def bw_pack_end_expand_nofill(self, widget, padding=0):
"""
"""
self.pack_end(widget, True, False, padding)
def bw_pack_end_noexpand_nofill(self, widget, padding=0):
"""
"""
self.pack_end(widget, False, False, padding)
class BWHBox(gtk.HBox, BWBox):
"""
"""
@@ -172,7 +165,6 @@ class BWHBox(gtk.HBox, BWBox):
gtk.HBox.__init__(self, homogeneous, spacing)
class BWVBox(gtk.VBox, BWBox):
"""
"""
@@ -182,7 +174,6 @@ class BWVBox(gtk.VBox, BWBox):
gtk.VBox.__init__(self, homogeneous, spacing)
class BWStatusbar(gtk.Statusbar, BWBox):
"""
"""
@@ -192,7 +183,6 @@ class BWStatusbar(gtk.Statusbar, BWBox):
gtk.HBox.__init__(self, homogeneous, spacing)
class BWTable(gtk.Table, BWBox):
"""
"""
@@ -207,14 +197,12 @@ class BWTable(gtk.Table, BWBox):
self.__last_point = (0, 0)
def bw_set_spacing(self, spacing):
"""
"""
self.set_row_spacings(spacing)
self.set_col_spacings(spacing)
def bw_resize(self, rows, columns):
"""
"""
@@ -223,11 +211,10 @@ class BWTable(gtk.Table, BWBox):
self.resize(rows, columns)
def bw_attach_next(self,
child,
xoptions=gtk.EXPAND|gtk.FILL,
yoptions=gtk.EXPAND|gtk.FILL,
xoptions=gtk.EXPAND | gtk.FILL,
yoptions=gtk.EXPAND | gtk.FILL,
xpadding=0,
ypadding=0):
"""
@@ -257,7 +244,6 @@ class BWTable(gtk.Table, BWBox):
self.__last_point = (row, column)
class BWScrolledWindow(gtk.ScrolledWindow):
"""
"""

View File

@@ -122,7 +122,6 @@
import gtk
class BWStockButton(gtk.Button):
"""
"""
@@ -138,7 +137,6 @@ class BWStockButton(gtk.Button):
self.set_image(self.__image)
class BWToggleStockButton(gtk.ToggleButton):
"""
"""

View File

@@ -123,7 +123,6 @@ import gtk
import gobject
class BWChangeableComboBoxEntry(gtk.ComboBoxEntry):
"""
"""
@@ -139,20 +138,17 @@ class BWChangeableComboBoxEntry(gtk.ComboBoxEntry):
self.__last_active = None
def __changed(self, widget):
"""
"""
if self.get_active() != -1:
self.__last_active = self.get_active()
def bw_get_lenght(self):
"""
"""
return len(self.__liststore)
def __entry_changed(self, widget):
"""
"""
@@ -163,7 +159,6 @@ class BWChangeableComboBoxEntry(gtk.ComboBoxEntry):
iter = self.get_model().get_iter((self.__last_active,))
self.__liststore.set_value(iter, 0, widget.get_text().strip())
def bw_get_active(self):
"""
"""
@@ -173,7 +168,6 @@ class BWChangeableComboBoxEntry(gtk.ComboBoxEntry):
return self.get_active()
# testing widget
if __name__ == "__main__":
@@ -182,7 +176,6 @@ if __name__ == "__main__":
"""
combo.append_text('New')
window = gtk.Window()
window.connect("destroy", lambda w: gtk.main_quit())

View File

@@ -139,13 +139,11 @@ class BWExpander(gtk.Expander):
self.add(self.__alignment)
def bw_set_label_text(self, text):
"""
"""
self.__label.bw_set_text(text)
def bw_add(self, widget):
"""
"""
@@ -154,7 +152,6 @@ class BWExpander(gtk.Expander):
self.__alignment.add(widget)
def bw_no_padding(self):
"""
"""

View File

@@ -122,7 +122,6 @@
import gtk
class BWFrame(gtk.Frame):
"""
"""
@@ -141,20 +140,17 @@ class BWFrame(gtk.Frame):
self.bw_set_label(label)
def bw_set_label(self, label):
"""
"""
self.set_label("<b>" + label + "</b>")
self.get_label_widget().set_use_markup(True)
def bw_add(self, widget):
"""
"""
self.__alignment.add(widget)
def bw_remove(self, widget):
"""
"""

View File

@@ -122,7 +122,6 @@
import gtk
class BWLabel(gtk.Label):
"""
"""
@@ -137,7 +136,6 @@ class BWLabel(gtk.Label):
self.set_line_wrap(True)
class BWSectionLabel(gtk.Label):
"""
"""
@@ -151,7 +149,6 @@ class BWSectionLabel(gtk.Label):
self.set_alignment(0, 0.50)
self.set_line_wrap(True)
def bw_set_text(self, text):
"""
"""

View File

@@ -135,7 +135,6 @@ class BWTextView(BWScrolledWindow):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -144,25 +143,21 @@ class BWTextView(BWScrolledWindow):
self.add_with_viewport(self.__textview)
def bw_set_auto_scroll(self, value):
"""
"""
self.__auto_scroll = value
def bw_set_editable(self, editable):
"""
"""
self.__textview.set_editable(False)
def bw_modify_font(self, font):
"""
"""
self.__textview.modify_font(font)
def bw_set_text(self, text):
"""
"""
@@ -171,27 +166,23 @@ class BWTextView(BWScrolledWindow):
if self.__auto_scroll:
self.bw_set_scroll_down()
def bw_get_text(self):
"""
"""
return self.__textbuffer.get_text(self.__textbuffer.get_start_iter(),
self.__textbuffer.get_end_iter())
def bw_set_scroll_down(self):
"""
"""
self.get_vadjustment().set_value(self.get_vadjustment().upper)
def bw_get_textbuffer(self):
"""
"""
return self.__textbuffer
class BWTextEditor(BWScrolledWindow):
"""
"""
@@ -205,7 +196,6 @@ class BWTextEditor(BWScrolledWindow):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -225,33 +215,28 @@ class BWTextEditor(BWScrolledWindow):
self.add_with_viewport(self.__hbox)
def __expose(self, widget, event):
"""
"""
# code to fix a gtk issue that don't show text correctly
self.__hbox.check_resize()
def bw_set_auto_scroll(self, value):
"""
"""
self.__auto_scroll = value
def bw_set_editable(self, editable):
"""
"""
self.__textview.set_editable(False)
def bw_modify_font(self, font):
"""
"""
self.__textview.modify_font(font)
self.__lineview.modify_font(font)
def bw_set_text(self, text):
"""
"""
@@ -273,14 +258,12 @@ class BWTextEditor(BWScrolledWindow):
self.__textbuffer.set_text("")
self.__linebuffer.set_text("")
def bw_get_text(self):
"""
"""
return self.__textbuffer.get_text(self.__textbuffer.get_start_iter(),
self.__textbuffer.get_end_iter())
def bw_set_scroll_down(self):
"""
"""

View File

@@ -125,7 +125,6 @@ from radialnet.bestwidgets import gtk_version_minor
PRIMARY_TEXT_MARKUP = '<span weight="bold" size="larger">%s</span>'
class BWAlertDialog(gtk.MessageDialog):
"""
"""
@@ -149,14 +148,12 @@ class BWAlertDialog(gtk.MessageDialog):
if gtk_version_minor > 4:
self.format_secondary_text(secondary_text)
def __destroy(self, dialog, id):
"""
"""
self.destroy()
class BWWindow(gtk.Window):
"""
"""

View File

@@ -130,7 +130,6 @@ class ArgvHandle:
"""
self.__argv = argv
def get_option(self, option):
"""
"""
@@ -143,20 +142,17 @@ class ArgvHandle:
return None
def has_option(self, option):
"""
"""
return option in self.__argv
def get_last_value(self):
"""
"""
return self.__argv[-1]
if __name__ == '__main__':
import sys

View File

@@ -141,31 +141,26 @@ class PolarCoordinate:
self.__t = t
"""Angle (theta) of polar coordinate in radians"""
def get_theta(self):
"""
"""
return math.degrees(self.__t)
def get_radius(self):
"""
"""
return self.__r
def set_theta(self, t):
"""
"""
self.__t = math.radians(t)
def set_radius(self, r):
"""
"""
self.__r = r
def get_coordinate(self):
"""
Set polar coordinate
@@ -174,7 +169,6 @@ class PolarCoordinate:
"""
return (self.__r, math.degrees(self.__t))
def set_coordinate(self, r, t):
"""
Set polar coordinate
@@ -186,7 +180,6 @@ class PolarCoordinate:
self.__r = r
self.__t = math.radians(t)
def to_cartesian(self):
"""
Convert polar in cartesian coordinate
@@ -199,12 +192,10 @@ class PolarCoordinate:
return (x, y)
class CartesianCoordinate:
"""
Class to implement a cartesian coordinate object
"""
def __init__(self, x=0, y=0):
"""
Constructor method of CartesianCoordinate class
@@ -218,7 +209,6 @@ class CartesianCoordinate:
self.__y = y
"""Y component of cartesian coordinate"""
def get_coordinate(self):
"""
Get cartesian coordinate
@@ -227,7 +217,6 @@ class CartesianCoordinate:
"""
return (self.__x, self.__y)
def set_coordinate(self, x, y):
"""
Set cartesian coordinate
@@ -239,25 +228,24 @@ class CartesianCoordinate:
self.__x = x
self.__y = y
def to_polar(self):
"""
Convert cartesian in polar coordinate
@rtype: tuple
@return: polar coordinates (r, t)
"""
r = math.sqrt(self.__x**2 + self.__y**2)
r = math.sqrt(self.__x ** 2 + self.__y ** 2)
if self.__x > 0:
if self.__y >= 0:
t = math.atan( self.__y / self.__x )
t = math.atan(self.__y / self.__x)
else:
t = math.atan( self.__y / self.__x ) + 2 * math.pi
t = math.atan(self.__y / self.__x) + 2 * math.pi
elif self.__x < 0:
t = math.atan( self.__y / self.__x ) + math.pi
t = math.atan(self.__y / self.__x) + math.pi
elif self.__x == 0:
@@ -273,12 +261,11 @@ class CartesianCoordinate:
return (r, t)
if __name__ == "__main__":
# Testing application
polar = PolarCoordinate(1, math.pi)
polar = PolarCoordinate(1, math.pi)
cartesian = CartesianCoordinate(-1, 0)
print polar.to_cartesian()

View File

@@ -135,15 +135,12 @@ class Node(object):
self.__edges = []
"""List of edges to other nodes"""
def get_data(self):
return self.__data
def set_data(self, data):
self.__data = data
def get_edge(self, dest):
"""
Return the edge connecting to dest, or None if none
@@ -153,19 +150,16 @@ class Node(object):
return edge
return None
def get_edges(self):
"""
Return the list of edges
"""
return self.__edges
def add_edge(self, edge):
self.__edges.append(edge)
class Edge:
"""
"""
@@ -176,41 +170,34 @@ class Edge:
self.__nodes = nodes
self.__weights_mean = None
def get_nodes(self):
"""
"""
return self.__nodes
def get_weights(self):
"""
"""
return self.__weights
def set_weights(self, weights):
"""
"""
self.__weights = weights
self.__weights_mean = sum(self.__weights) / len(self.__weights)
def add_weight(self, weight):
"""
"""
self.__weights.append(weight)
self.__weights_mean = sum(self.__weights) / len(self.__weights)
def get_weights_mean(self):
"""
"""
return self.__weights_mean
class Graph:
"""
Network Graph class
@@ -227,19 +214,16 @@ class Graph:
self.__max_edge_mean_value = None
self.__min_edge_mean_value = None
def set_nodes(self, nodes):
"""
"""
self.__nodes = nodes
def get_nodes(self):
"""
"""
return self.__nodes
def get_number_of_nodes(self):
"""
Get the number of nodes in graph
@@ -248,7 +232,6 @@ class Graph:
"""
return len(self.__nodes)
def set_main_node(self, node):
"""
Set the main node
@@ -257,7 +240,6 @@ class Graph:
"""
self.__main_node = node
def get_main_node(self):
"""
Get the main node
@@ -266,7 +248,6 @@ class Graph:
"""
return self.__main_node
def set_connection(self, a, b, weight=None):
"""
Set node connections
@@ -287,12 +268,13 @@ class Graph:
edge.add_weight(weight)
mean_weight = edge.get_weights_mean()
if self.__min_edge_mean_value is None or mean_weight < self.__min_edge_mean_value:
if (self.__min_edge_mean_value is None or
mean_weight < self.__min_edge_mean_value):
self.__min_edge_mean_value = mean_weight
if self.__max_edge_mean_value is None or mean_weight > self.__max_edge_mean_value:
if (self.__max_edge_mean_value is None or
mean_weight > self.__max_edge_mean_value):
self.__max_edge_mean_value = mean_weight
def get_edges(self):
"""
An iterator that yields all edges
@@ -302,7 +284,6 @@ class Graph:
if edge.get_nodes()[0] == node:
yield edge
def get_node_connections(self, node):
"""
"""
@@ -319,16 +300,12 @@ class Graph:
return connections
def get_max_edge_mean_weight(self):
"""
"""
return self.__max_edge_mean_value
def get_min_edge_mean_weight(self):
"""
"""
return self.__min_edge_mean_value

View File

@@ -122,7 +122,7 @@
import os
INFO = {'name' : 'RadialNet',
INFO = {'name': 'RadialNet',
'version': '0.44',
'website': 'http://www.dca.ufrn.br/~joaomedeiros/radialnet/',
'authors': ['João Paulo de Souza Medeiros'],

View File

@@ -136,7 +136,6 @@ class Linear2DInterpolator:
self.__interpolated_points = []
"""Interpolated points vector"""
def set_start_point(self, a, b):
"""
Set initial coordinate
@@ -148,7 +147,6 @@ class Linear2DInterpolator:
"""
self.__start_point = (a, b)
def set_final_point(self, a, b):
"""
Set final coordinate
@@ -159,7 +157,6 @@ class Linear2DInterpolator:
"""
self.__final_point = (a, b)
def get_weighed_points(self, number_of_pass, pass_vector):
"""
Return the vector of coordinates between the initial and final
@@ -188,7 +185,6 @@ class Linear2DInterpolator:
return self.__interpolated_points
def get_points(self, number_of_pass):
"""
Return the vector of coordinates between the initial and final
@@ -213,7 +209,6 @@ class Linear2DInterpolator:
return self.__interpolated_points
if __name__ == "__main__":
# Testing application
@@ -224,4 +219,3 @@ if __name__ == "__main__":
i.set_final_point(1, 1)
print len(i.get_points(10)), i.get_points(10)

View File

@@ -124,14 +124,12 @@ import xml.sax.saxutils
from xml.sax.xmlreader import AttributesImpl as Attributes
def convert_to_utf8(text):
"""
"""
return text.encode('utf8', 'replace')
class XMLNode:
"""
"""
@@ -143,70 +141,59 @@ class XMLNode:
self.__attrs = dict()
self.__children = []
def set_text(self, text):
"""
"""
self.__text = text
def get_text(self):
"""
"""
return self.__text
def set_name(self, name):
"""
"""
self.__name = name
def get_name(self):
"""
"""
return self.__name
def add_attr(self, key, value):
"""
"""
self.__attrs[key] = value
def add_child(self, child):
"""
"""
self.__children.append(child)
def get_keys(self):
"""
"""
return self.__attrs.keys()
def get_attr(self, attr):
"""
"""
if self.__attrs.has_key(attr):
if attr in self.__attrs:
return self.__attrs[attr]
return None
def get_attrs(self):
"""
"""
return self.__attrs
def get_children(self):
"""
"""
return self.__children
def query_children(self, name, attr, value, first=False, deep=False):
"""
"""
@@ -216,7 +203,7 @@ class XMLNode:
if child.get_name() == name:
if child.get_attrs().has_key(attr):
if attr in child.get_attrs():
c_value = child.get_attr(attr)
@@ -243,7 +230,6 @@ class XMLNode:
return result
def search_children(self, name, first=False, deep=False):
"""
"""
@@ -276,7 +262,6 @@ class XMLNode:
return result
class XMLWriter(xml.sax.saxutils.XMLGenerator):
"""
"""
@@ -287,13 +272,11 @@ class XMLWriter(xml.sax.saxutils.XMLGenerator):
self.__root = root
def set_root(self, root):
"""
"""
self.__root = root
def write(self):
"""
"""
@@ -301,7 +284,6 @@ class XMLWriter(xml.sax.saxutils.XMLGenerator):
self.write_xml_node([self.__root])
self.endDocument()
def write_xml_node(self, root):
"""
"""
@@ -317,7 +299,6 @@ class XMLWriter(xml.sax.saxutils.XMLGenerator):
self.endElement(child.get_name())
class XMLReader(xml.sax.ContentHandler):
"""
"""
@@ -330,41 +311,35 @@ class XMLReader(xml.sax.ContentHandler):
self.__file = file
self.__root = None
self.__parser = xml.sax.make_parser();
self.__parser.setContentHandler(self);
self.__parser = xml.sax.make_parser()
self.__parser.setContentHandler(self)
def set_file(self, file, root):
"""
"""
self.__file = file
def get_file(self):
"""
"""
return self.__file
def get_root(self):
"""
"""
return self.__root
def parse(self):
"""
"""
if self.__file != None:
self.__parser.parse(self.__file)
def startDocument(self):
"""
"""
pass
def startElement(self, name, attrs):
"""
"""
@@ -384,7 +359,6 @@ class XMLReader(xml.sax.ContentHandler):
self.__status.append(node)
def endElement(self, name):
"""
"""
@@ -393,20 +367,17 @@ class XMLReader(xml.sax.ContentHandler):
self.__text = ""
self.__status.pop()
def endDocument(self):
"""
"""
pass
def characters(self, text):
"""
"""
self.__text += text
if __name__ == "__main__":
import sys

View File

@@ -118,4 +118,3 @@
# * Nmap, and also available from https://svn.nmap.org/nmap/COPYING *
# * *
# ***************************************************************************/

View File

@@ -135,7 +135,6 @@ from radialnet.bestwidgets.boxes import *
DIMENSION = (640, 480)
class Application(BWMainWindow):
"""
"""
@@ -149,7 +148,6 @@ class Application(BWMainWindow):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -188,7 +186,6 @@ class Application(BWMainWindow):
self.__fisheye.hide()
self.__toolbar.disable_controls()
def parse_nmap_xml_file(self, file):
"""
"""
@@ -217,7 +214,6 @@ class Application(BWMainWindow):
return True
def start(self):
"""
"""

View File

@@ -143,7 +143,6 @@ OPTIONS = ['address',
REFRESH_RATE = 500
class ControlWidget(BWVBox):
"""
"""
@@ -157,7 +156,6 @@ class ControlWidget(BWVBox):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -179,6 +177,7 @@ def try_set_tooltip_text(widget, text):
# The set_tooltip_text method was introduced in PyGTK 2.12.
pass
class ControlAction(BWExpander):
"""
"""
@@ -192,7 +191,6 @@ class ControlAction(BWExpander):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -253,7 +251,6 @@ class ControlAction(BWExpander):
self.__region_color.set_no_show_all(True)
self.__region_color.hide()
def __change_pointer(self, widget, pointer):
"""
"""
@@ -265,14 +262,12 @@ class ControlAction(BWExpander):
else:
self.__region_color.hide()
def __change_region(self, widget):
"""
"""
self.radialnet.set_region_color(self.__region_color.get_active())
class ControlVariableWidget(gtk.DrawingArea):
"""
"""
@@ -307,7 +302,6 @@ class ControlVariableWidget(gtk.DrawingArea):
gobject.timeout_add(REFRESH_RATE, self.verify_value)
def verify_value(self):
"""
"""
@@ -318,7 +312,6 @@ class ControlVariableWidget(gtk.DrawingArea):
return True
def button_press(self, widget, event):
"""
"""
@@ -331,7 +324,6 @@ class ControlVariableWidget(gtk.DrawingArea):
self.__active_increment = True
self.__increment_value()
def button_release(self, widget, event):
"""
"""
@@ -342,7 +334,6 @@ class ControlVariableWidget(gtk.DrawingArea):
self.queue_draw()
def motion_notify(self, widget, event):
"""
Drawing callback
@@ -363,7 +354,6 @@ class ControlVariableWidget(gtk.DrawingArea):
self.queue_draw()
def expose(self, widget, event):
"""
Drawing callback
@@ -381,7 +371,6 @@ class ControlVariableWidget(gtk.DrawingArea):
return True
def __draw(self):
"""
"""
@@ -394,7 +383,7 @@ class ControlVariableWidget(gtk.DrawingArea):
# draw line
self.context.set_line_width(1)
self.context.set_dash([1,2])
self.context.set_dash([1, 2])
self.context.move_to(self.__radius,
yc + self.__radius)
self.context.line_to(2 * xc - 5,
@@ -402,7 +391,7 @@ class ControlVariableWidget(gtk.DrawingArea):
self.context.stroke()
# draw text
self.context.set_dash([1,0])
self.context.set_dash([1, 0])
self.context.set_font_size(10)
width = self.context.text_extents(self.__variable_name)[2]
@@ -428,7 +417,6 @@ class ControlVariableWidget(gtk.DrawingArea):
self.context.set_source_rgb(0.0, 0.0, 0.0)
self.context.stroke()
def __button_is_clicked(self, pointer):
"""
"""
@@ -440,7 +428,6 @@ class ControlVariableWidget(gtk.DrawingArea):
return False
def __increment_value(self):
"""
"""
@@ -453,20 +440,17 @@ class ControlVariableWidget(gtk.DrawingArea):
gobject.timeout_add(self.__increment_time,
self.__increment_value)
def set_value_function(self, value):
"""
"""
self.__value = value
def set_update_function(self, update):
"""
"""
self.__update = update
class ControlVariable(BWHBox):
"""
"""
@@ -485,7 +469,6 @@ class ControlVariable(BWHBox):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -516,14 +499,12 @@ class ControlVariable(BWHBox):
self.bw_pack_start_expand_fill(self.__control)
self.bw_pack_start_noexpand_nofill(self.__right_button)
def __pressed(self, widget, increment):
"""
"""
self.__increment = True
self.__increment_function(increment)
def __increment_function(self, increment):
"""
"""
@@ -536,15 +517,12 @@ class ControlVariable(BWHBox):
self.__increment_function,
increment)
def __released(self, widget):
"""
"""
self.__increment = False
class ControlFisheye(BWVBox):
"""
"""
@@ -559,7 +537,6 @@ class ControlFisheye(BWVBox):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -606,7 +583,6 @@ class ControlFisheye(BWVBox):
gobject.timeout_add(REFRESH_RATE, self.__update_fisheye)
def __update_fisheye(self):
"""
"""
@@ -648,7 +624,6 @@ class ControlFisheye(BWVBox):
return True
def active_fisheye(self):
"""
"""
@@ -656,13 +631,11 @@ class ControlFisheye(BWVBox):
self.__change_ring()
self.__change_interest()
def deactive_fisheye(self):
"""
"""
self.radialnet.set_fisheye(False)
def __change_ring(self, widget=None):
"""
"""
@@ -671,7 +644,6 @@ class ControlFisheye(BWVBox):
else:
self.__ring.set_value(self.radialnet.get_fisheye_ring())
def __change_interest(self, widget=None):
"""
"""
@@ -680,7 +652,6 @@ class ControlFisheye(BWVBox):
else:
self.__interest.set_value(self.radialnet.get_fisheye_interest())
def __change_spread(self, widget=None):
"""
"""
@@ -690,7 +661,6 @@ class ControlFisheye(BWVBox):
self.__spread.set_value(self.radialnet.get_fisheye_spread())
class ControlInterpolation(BWExpander):
"""
"""
@@ -703,14 +673,14 @@ class ControlInterpolation(BWExpander):
self.__create_widgets()
def __create_widgets(self):
"""
"""
self.__vbox = BWVBox()
self.__cartesian_radio = gtk.RadioButton(None, _('Cartesian'))
self.__polar_radio = gtk.RadioButton(self.__cartesian_radio, _('Polar'))
self.__polar_radio = gtk.RadioButton(
self.__cartesian_radio, _('Polar'))
self.__cartesian_radio.connect('toggled',
self.__change_system,
INTERPOLATION_CARTESIAN)
@@ -741,7 +711,6 @@ class ControlInterpolation(BWExpander):
gobject.timeout_add(REFRESH_RATE, self.__update_animation)
def __update_animation(self):
"""
"""
@@ -755,7 +724,6 @@ class ControlInterpolation(BWExpander):
return True
def __change_system(self, widget, value):
"""
"""
@@ -769,7 +737,6 @@ class ControlInterpolation(BWExpander):
else:
self.__polar_radio.set_active(True)
def __change_frames(self, widget):
"""
"""
@@ -777,7 +744,6 @@ class ControlInterpolation(BWExpander):
self.__frames.set_value(self.radialnet.get_number_of_frames())
class ControlLayout(BWExpander):
"""
"""
@@ -790,7 +756,6 @@ class ControlLayout(BWExpander):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -811,7 +776,6 @@ class ControlLayout(BWExpander):
self.__check_layout()
def __check_layout(self):
"""
"""
@@ -823,14 +787,12 @@ class ControlLayout(BWExpander):
return True
def __force_update(self, widget):
"""
"""
self.__fisheye_ring = self.radialnet.get_fisheye_ring()
self.radialnet.update_layout()
def __change_layout(self, widget):
"""
"""
@@ -841,7 +803,6 @@ class ControlLayout(BWExpander):
self.__check_layout()
class ControlRingGap(BWVBox):
"""
"""
@@ -854,7 +815,6 @@ class ControlRingGap(BWVBox):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -878,7 +838,6 @@ class ControlRingGap(BWVBox):
self.bw_pack_start_noexpand_nofill(self.__radius)
self.bw_pack_start_noexpand_nofill(self.__lower_hbox)
def __change_lower(self, widget):
"""
"""
@@ -886,7 +845,6 @@ class ControlRingGap(BWVBox):
self.__adjustment.set_value(self.radialnet.get_min_ring_gap())
class ControlOptions(BWScrolledWindow):
"""
"""
@@ -902,7 +860,6 @@ class ControlOptions(BWScrolledWindow):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -943,23 +900,23 @@ class ControlOptions(BWScrolledWindow):
gobject.timeout_add(REFRESH_RATE, self.__update_options)
def __update_options(self):
"""
"""
model = self.__liststore
model[OPTIONS.index('address')][0] = self.radialnet.get_show_address()
model[OPTIONS.index('hostname')][0] = self.radialnet.get_show_hostname()
model[OPTIONS.index('hostname')][0] = \
self.radialnet.get_show_hostname()
model[OPTIONS.index('icon')][0] = self.radialnet.get_show_icon()
model[OPTIONS.index('latency')][0] = self.radialnet.get_show_latency()
model[OPTIONS.index('ring')][0] = self.radialnet.get_show_ring()
model[OPTIONS.index('region')][0] = self.radialnet.get_show_region()
model[OPTIONS.index('slow in/out')][0] = self.radialnet.get_slow_inout()
model[OPTIONS.index('slow in/out')][0] = \
self.radialnet.get_slow_inout()
return True
def __change_option(self, cell, option, model):
"""
"""
@@ -988,7 +945,6 @@ class ControlOptions(BWScrolledWindow):
self.radialnet.set_slow_inout(model[option][0])
class ControlView(BWExpander):
"""
"""
@@ -1002,7 +958,6 @@ class ControlView(BWExpander):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -1026,7 +981,6 @@ class ControlView(BWExpander):
self.bw_add(self.__vbox)
class ControlNavigation(gtk.DrawingArea):
"""
"""
@@ -1047,12 +1001,12 @@ class ControlNavigation(gtk.DrawingArea):
self.__move_position = (0, 0)
self.__move_addition = [(-1, 0),
(-1,-1),
( 0,-1),
( 1,-1),
( 1, 0),
( 1, 1),
( 0, 1),
(-1, -1),
(0, -1),
(1, -1),
(1, 0),
(1, 1),
(0, 1),
(-1, 1)]
self.__move_factor = 1
@@ -1086,7 +1040,6 @@ class ControlNavigation(gtk.DrawingArea):
self.__rotate_node.set_coordinate(40, self.radialnet.get_rotation())
def key_press(self, widget, event):
"""
"""
@@ -1096,7 +1049,6 @@ class ControlNavigation(gtk.DrawingArea):
return True
def key_release(self, widget, event):
"""
"""
@@ -1106,13 +1058,11 @@ class ControlNavigation(gtk.DrawingArea):
return True
def enter_notify(self, widget, event):
"""
"""
return False
def leave_notify(self, widget, event):
"""
"""
@@ -1120,7 +1070,6 @@ class ControlNavigation(gtk.DrawingArea):
return False
def button_press(self, widget, event):
"""
Drawing callback
@@ -1159,7 +1108,6 @@ class ControlNavigation(gtk.DrawingArea):
return False
def button_release(self, widget, event):
"""
Drawing callback
@@ -1181,7 +1129,6 @@ class ControlNavigation(gtk.DrawingArea):
return False
def motion_notify(self, widget, event):
"""
Drawing callback
@@ -1213,7 +1160,6 @@ class ControlNavigation(gtk.DrawingArea):
return False
def expose(self, widget, event):
"""
Drawing callback
@@ -1231,7 +1177,6 @@ class ControlNavigation(gtk.DrawingArea):
return False
def __draw_rotate_control(self):
"""
"""
@@ -1251,14 +1196,14 @@ class ControlNavigation(gtk.DrawingArea):
self.context.stroke()
# draw arc
self.context.set_dash([1,2])
self.context.set_dash([1, 2])
self.context.arc(xc, yc, 40, 0, 2 * math.pi)
self.context.set_source_rgb(0.0, 0.0, 0.0)
self.context.set_line_width(1)
self.context.stroke()
# draw node
self.context.set_dash([1,0])
self.context.set_dash([1, 0])
self.context.arc(xc + x, yc - y, self.__rotate_radius, 0, 2 * math.pi)
if self.__rotating == True:
@@ -1274,14 +1219,13 @@ class ControlNavigation(gtk.DrawingArea):
return False
def __draw_move_control(self):
"""
"""
xc, yc = self.__center_of_widget
pc = PolarCoordinate()
self.context.set_dash([1,1])
self.context.set_dash([1, 1])
self.context.arc(xc, yc, 23, 0, 2 * math.pi)
self.context.set_source_rgb(0.0, 0.0, 0.0)
self.context.set_line_width(1)
@@ -1292,13 +1236,14 @@ class ControlNavigation(gtk.DrawingArea):
pc.set_coordinate(23, 45 * i)
x, y = pc.to_cartesian()
self.context.set_dash([1,1])
self.context.set_dash([1, 1])
self.context.move_to(xc, yc)
self.context.line_to(xc + x, yc - y)
self.context.stroke()
self.context.set_dash([1,0])
self.context.arc(xc + x, yc - y, self.__move_radius, 0, 2 * math.pi)
self.context.set_dash([1, 0])
self.context.arc(
xc + x, yc - y, self.__move_radius, 0, 2 * math.pi)
if i == self.__moving:
self.context.set_source_rgb(0.0, 0.0, 0.0)
@@ -1322,7 +1267,6 @@ class ControlNavigation(gtk.DrawingArea):
return False
def __draw(self):
"""
Drawing method
@@ -1338,7 +1282,6 @@ class ControlNavigation(gtk.DrawingArea):
return False
def __move_in_direction(self, direction):
"""
"""
@@ -1360,7 +1303,6 @@ class ControlNavigation(gtk.DrawingArea):
return False
def __rotate_is_clicked(self, pointer):
"""
"""
@@ -1375,7 +1317,6 @@ class ControlNavigation(gtk.DrawingArea):
return False
def __center_is_clicked(self, pointer):
"""
"""
@@ -1388,7 +1329,6 @@ class ControlNavigation(gtk.DrawingArea):
return False
def __move_is_clicked(self, pointer):
"""
"""
@@ -1409,5 +1349,3 @@ class ControlNavigation(gtk.DrawingArea):
return i
return None

View File

@@ -126,7 +126,6 @@ from radialnet.core.Info import INFO
from radialnet.gui.Image import Pixmaps
class AboutDialog(gtk.AboutDialog):
"""
"""
@@ -146,7 +145,6 @@ class AboutDialog(gtk.AboutDialog):
self.connect('response', self.__destroy)
def __destroy(self, dialog, id):
"""
"""

View File

@@ -138,7 +138,6 @@ DIMENSION = (700, 400)
IP_RE = '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
class HostsViewer(BWMainWindow):
"""
"""
@@ -155,7 +154,6 @@ class HostsViewer(BWMainWindow):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -170,8 +168,6 @@ class HostsViewer(BWMainWindow):
self.add(self.__panel)
def change_notebook(self, node):
"""
"""
@@ -187,7 +183,6 @@ class HostsViewer(BWMainWindow):
self.__panel.add2(self.__view)
class HostsList(gtk.ScrolledWindow):
"""
"""
@@ -203,7 +198,6 @@ class HostsList(gtk.ScrolledWindow):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -239,16 +233,16 @@ class HostsList(gtk.ScrolledWindow):
column = gtk.TreeViewColumn(HOSTS_HEADER[i],
self.__cell,
text = i)
text=i)
self.__hosts_column.append(column)
self.__hosts_column[i].set_reorderable(True)
self.__hosts_column[i].set_resizable(True)
self.__hosts_column[i].set_attributes(self.__cell,
text = i,
background = 3,
editable = 4)
text=i,
background=3,
editable=4)
self.__hosts_treeview.append_column(self.__hosts_column[2])
@@ -262,7 +256,6 @@ class HostsList(gtk.ScrolledWindow):
self.__hosts_treeview.set_cursor((0,))
self.__cursor_callback(self.__hosts_treeview)
def __cursor_callback(self, widget):
"""
"""
@@ -276,7 +269,6 @@ class HostsList(gtk.ScrolledWindow):
self.__parent.change_notebook(node)
def __host_sort(self, treemodel, iter1, iter2):
"""
"""

View File

@@ -128,7 +128,7 @@ from zenmapCore.Paths import Path
FORMAT_RGBA = 4
FORMAT_RGB = 3
FORMAT_RGB = 3
def get_pixels_for_cairo_image_surface(pixbuf):
@@ -144,16 +144,16 @@ def get_pixels_for_cairo_image_surface(pixbuf):
j = 0
while i < len(pixbuf.get_pixels()):
b, g, r = pixbuf.get_pixels()[i:i+FORMAT_RGB]
b, g, r = pixbuf.get_pixels()[i:i + FORMAT_RGB]
if format == FORMAT_RGBA:
a = pixbuf.get_pixels()[i + FORMAT_RGBA - 1]
elif format == FORMAT_RGB:
a = '\xff'
else:
raise TypeError, 'unknown image format'
raise TypeError('unknown image format')
data[j:j+FORMAT_RGBA] = array.ArrayType('c', [r, g, b, a])
data[j:j + FORMAT_RGBA] = array.ArrayType('c', [r, g, b, a])
i += format
j += FORMAT_RGBA
@@ -170,13 +170,11 @@ class Image:
self.__path = path
self.__cache = dict()
def set_path(self, path):
"""
"""
self.__path = path
def get_pixbuf(self, icon, image_type='png'):
"""
"""
@@ -186,11 +184,11 @@ class Image:
if icon + image_type not in self.__cache.keys():
file = self.get_icon(icon, image_type)
self.__cache[icon + image_type] = gtk.gdk.pixbuf_new_from_file(file)
self.__cache[icon + image_type] = \
gtk.gdk.pixbuf_new_from_file(file)
return self.__cache[icon + image_type]
def get_icon(self, icon, image_type='png'):
"""
"""
@@ -200,7 +198,6 @@ class Image:
return os.path.join(self.__path, icon + "." + image_type)
class Pixmaps(Image):
"""
"""
@@ -210,7 +207,6 @@ class Pixmaps(Image):
Image.__init__(self, os.path.join(Path.pixmaps_dir, "radialnet"))
class Icons(Image):
"""
"""
@@ -220,7 +216,6 @@ class Icons(Image):
Image.__init__(self, os.path.join(Path.pixmaps_dir, "radialnet"))
class Application(Image):
"""
"""

View File

@@ -129,27 +129,27 @@ from radialnet.bestwidgets.labels import *
from radialnet.bestwidgets.textview import *
PORTS_HEADER = [_('Port'), _('Protocol'), _('State'), _('Service'), _('Method')]
PORTS_HEADER = [
_('Port'), _('Protocol'), _('State'), _('Service'), _('Method')]
EXTRAPORTS_HEADER = [_('Count'), _('State'), _('Reasons')]
SERVICE_COLORS = {'open' : '#ffd5d5',
'closed' : '#d5ffd5',
'filtered' : '#ffffd5',
'unfiltered' : '#ffd5d5',
'open|filtered' : '#ffd5d5',
'closed|filtered' : '#d5ffd5'}
SERVICE_COLORS = {'open': '#ffd5d5',
'closed': '#d5ffd5',
'filtered': '#ffffd5',
'unfiltered': '#ffd5d5',
'open|filtered': '#ffd5d5',
'closed|filtered': '#d5ffd5'}
UNKNOWN_SERVICE_COLOR = '#d5d5d5'
TRACE_HEADER = [_('TTL'), _('RTT'), _('IP'), _('Hostname')]
TRACE_TEXT = _("""\
Traceroute on port <b>%s/%s</b> totalized <b>%d</b> known hops.\
""")
TRACE_TEXT = _(
"Traceroute on port <b>%s/%s</b> totalized <b>%d</b> known hops.")
NO_TRACE_TEXT = _("No traceroute information available.")
HOP_COLOR = {'known' : '#ffffff',
'unknown' : '#cccccc'}
HOP_COLOR = {'known': '#ffffff',
'unknown': '#cccccc'}
SYSTEM_ADDRESS_TEXT = "[%s] %s"
@@ -162,6 +162,7 @@ TCP_SEQ_NOTE = _("""\
<b>*</b> TCP sequence <i>index</i> equal to %d and <i>difficulty</i> is "%s".\
""")
def get_service_color(state):
color = SERVICE_COLORS.get(state)
if color is None:
@@ -182,7 +183,6 @@ class NodeNotebook(gtk.Notebook):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -197,7 +197,6 @@ class NodeNotebook(gtk.Notebook):
self.append_page(self.__trace_page, BWLabel(_('Traceroute')))
class ServicesPage(gtk.Notebook):
"""
"""
@@ -213,7 +212,6 @@ class ServicesPage(gtk.Notebook):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -256,13 +254,13 @@ class ServicesPage(gtk.Notebook):
color = get_service_color(port['state']['state'])
if port['service'].has_key('name'):
if 'name' in port['service']:
service_name = port['service']['name']
else:
service_name = _('<unknown>')
if port['service'].has_key('method'):
if 'method' in port['service']:
service_method = port['service']['method']
else:
@@ -330,7 +328,7 @@ class ServicesPage(gtk.Notebook):
column = gtk.TreeViewColumn(PORTS_HEADER[i],
self.__cell,
text = i)
text=i)
self.__ports_column.append(column)
@@ -338,9 +336,9 @@ class ServicesPage(gtk.Notebook):
self.__ports_column[i].set_resizable(True)
self.__ports_column[i].set_sort_column_id(i)
self.__ports_column[i].set_attributes(self.__cell,
text = i,
background = 5,
editable = 6)
text=i,
background=5,
editable=6)
self.__ports_treeview.append_column(self.__ports_column[i])
@@ -364,12 +362,9 @@ class ServicesPage(gtk.Notebook):
color = get_service_color(xports['state'])
number_of_xports += xports['count']
reference = self.__xports_store.append(None,
[xports['count'],
xports['state'],
", ".join(xports['reason']),
color,
True])
reference = self.__xports_store.append(
None, [xports['count'], xports['state'],
", ".join(xports['reason']), color, True])
for xreason in xports['all_reason']:
self.__xports_store.append(reference,
@@ -385,7 +380,7 @@ class ServicesPage(gtk.Notebook):
column = gtk.TreeViewColumn(EXTRAPORTS_HEADER[i],
self.__cell,
text = i)
text=i)
self.__xports_column.append(column)
@@ -393,9 +388,9 @@ class ServicesPage(gtk.Notebook):
self.__xports_column[i].set_resizable(True)
self.__xports_column[i].set_sort_column_id(i)
self.__xports_column[i].set_attributes(self.__cell,
text = i,
background = 3,
editable = 4)
text=i,
background=3,
editable=4)
self.__xports_treeview.append_column(self.__xports_column[i])
@@ -411,7 +406,6 @@ class ServicesPage(gtk.Notebook):
if len(self.__text) > 0:
self.__select_combobox.set_active(0)
def __change_text_value(self, widget):
"""
"""
@@ -433,7 +427,6 @@ class SystemPage(BWScrolledWindow):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -516,7 +509,8 @@ class SystemPage(BWScrolledWindow):
sequences = self.__node.get_info('sequences')
if len(sequences) > 0:
self.__sequences_frame.bw_add(self.__create_sequences_widget(sequences))
self.__sequences_frame.bw_add(
self.__create_sequences_widget(sequences))
# operating system information widgets
self.__os = gtk.Notebook()
@@ -525,7 +519,7 @@ class SystemPage(BWScrolledWindow):
if os != None:
if os.has_key('matches'):
if 'matches' in os:
self.__match_scroll = BWScrolledWindow()
@@ -550,15 +544,15 @@ class SystemPage(BWScrolledWindow):
column = gtk.TreeViewColumn(OSMATCH_HEADER[i],
self.__cell,
text = i)
text=i)
self.__match_column.append(column)
self.__match_column[i].set_reorderable(True)
self.__match_column[i].set_resizable(True)
self.__match_column[i].set_attributes(self.__cell,
text = i,
editable = 3)
text=i,
editable=3)
self.__match_column[i].set_sort_column_id(i)
self.__match_treeview.append_column(self.__match_column[i])
@@ -567,7 +561,7 @@ class SystemPage(BWScrolledWindow):
self.__os.append_page(self.__match_scroll, BWLabel(_('Match')))
if os.has_key('classes'):
if 'classes' in os:
self.__class_scroll = BWScrolledWindow()
@@ -584,7 +578,7 @@ class SystemPage(BWScrolledWindow):
os_gen = ''
if os_class.has_key('os_gen'):
if 'os_gen' in os_class:
os_gen = os_class['os_gen']
self.__class_store.append([os_class['accuracy'],
@@ -600,15 +594,15 @@ class SystemPage(BWScrolledWindow):
column = gtk.TreeViewColumn(OSCLASS_HEADER[i],
self.__cell,
text = i)
text=i)
self.__class_column.append(column)
self.__class_column[i].set_reorderable(True)
self.__class_column[i].set_resizable(True)
self.__class_column[i].set_attributes(self.__cell,
text = i,
editable = 5)
text=i,
editable=5)
self.__class_column[i].set_sort_column_id(i)
self.__class_treeview.append_column(self.__class_column[i])
@@ -630,7 +624,7 @@ class SystemPage(BWScrolledWindow):
self.__fp_vbox = BWVBox()
if os.has_key('used_ports'):
if 'used_ports' in os:
used_ports = os['used_ports']
@@ -692,7 +686,8 @@ class SystemPage(BWScrolledWindow):
tcp_note.set_selectable(True)
tcp_note.set_line_wrap(False)
tcp_note.set_alignment(1.0, 0.5)
tcp_note.set_markup(TCP_SEQ_NOTE % (tcp['index'], tcp['difficulty']))
tcp_note.set_markup(
TCP_SEQ_NOTE % (tcp['index'], tcp['difficulty']))
table.attach(tcp_note, 0, 3, 4, 5)
@@ -733,8 +728,6 @@ class SystemPage(BWScrolledWindow):
return table
class TraceroutePage(BWVBox):
"""
"""
@@ -748,7 +741,6 @@ class TraceroutePage(BWVBox):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -805,23 +797,22 @@ class TraceroutePage(BWVBox):
HOP_COLOR['unknown'],
True])
self.__trace_column = list()
for i in range(len(TRACE_HEADER)):
column = gtk.TreeViewColumn(TRACE_HEADER[i],
self.__cell,
text = i)
text=i)
self.__trace_column.append(column)
self.__trace_column[i].set_reorderable(True)
self.__trace_column[i].set_resizable(True)
self.__trace_column[i].set_attributes(self.__cell,
text = i,
background = 4,
editable = 5)
text=i,
background=4,
editable=5)
self.__trace_treeview.append_column(self.__trace_column[i])

View File

@@ -151,7 +151,6 @@ class NodeWindow(BWWindow):
self.__icon = Application()
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -168,7 +167,8 @@ class NodeWindow(BWWindow):
self.__color_image.set_from_file(self.__icon.get_icon('border'))
self.__color_box.add(self.__color_image)
self.__color_box.set_size_request(15, 15)
r, g, b = drawing.cairo_to_gdk_color(self.__node.get_draw_info('color'))
r, g, b = drawing.cairo_to_gdk_color(
self.__node.get_draw_info('color'))
self.__color_box.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(r, g, b))
# title with the node ip and hostname

File diff suppressed because it is too large Load Diff

View File

@@ -133,8 +133,8 @@ TYPES = ((_("By extension"), None, None),
(_("PNG"), RadialNet.FILE_TYPE_PNG, ".png"),
(_("PostScript"), RadialNet.FILE_TYPE_PS, ".ps"),
(_("SVG"), RadialNet.FILE_TYPE_SVG, ".svg"))
# Build a reverse index of extensions to file types, for the "By extension" file
# type.
# Build a reverse index of extensions to file types, for the "By extension"
# file type.
EXTENSIONS = {}
for type in TYPES:
if type[2] is not None:
@@ -181,7 +181,8 @@ class SaveDialog(zenmapGUI.FileChoosers.UnicodeFileChooserDialog):
self.set_current_folder(dir)
# Find the recommended extension.
new_ext = self.__combo.get_model().get_value(self.__combo.get_active_iter(), 2)
new_ext = self.__combo.get_model().get_value(
self.__combo.get_active_iter(), 2)
if new_ext is not None:
# Change the filename to use the recommended extension.
root, ext = os.path.splitext(basename)
@@ -197,15 +198,17 @@ class SaveDialog(zenmapGUI.FileChoosers.UnicodeFileChooserDialog):
if ext == "":
filename = self.get_filename() or ""
dir, basename = os.path.split(filename)
alert = HIGAlertDialog(message_format=_("No filename extension"),
secondary_text=_("""\
The filename "%s" does not have an extension, and no specific file type was chosen.
Enter a known extension or select the file type from the list.\
""" % basename))
alert = HIGAlertDialog(
message_format=_("No filename extension"),
secondary_text=_("""\
The filename "%s" does not have an extension, \
and no specific file type was chosen.
Enter a known extension or select the file type from the list.""" % basename))
else:
alert = HIGAlertDialog(message_format=_("Unknown filename extension"),
secondary_text=_("""\
alert = HIGAlertDialog(
message_format=_("Unknown filename extension"),
secondary_text=_("""\
There is no file type known for the filename extension "%s".
Enter a known extension or select the file type from the list.\
""") % self.__get_extension())
@@ -218,7 +221,8 @@ Enter a known extension or select the file type from the list.\
return os.path.splitext(self.get_filename())[1]
def get_filetype(self):
filetype = self.__combo.get_model().get_value(self.__combo.get_active_iter(), 1)
filetype = self.__combo.get_model().get_value(
self.__combo.get_active_iter(), 1)
if filetype is None:
# Guess based on extension.
return EXTENSIONS.get(self.__get_extension())

View File

@@ -136,7 +136,6 @@ HIDE = False
REFRESH_RATE = 500
class ToolsMenu(gtk.Menu):
"""
"""
@@ -149,7 +148,6 @@ class ToolsMenu(gtk.Menu):
self.__create_items()
def __create_items(self):
"""
"""
@@ -163,7 +161,6 @@ class ToolsMenu(gtk.Menu):
self.__hosts.show_all()
def __hosts_viewer_callback(self, widget):
"""
"""
@@ -171,20 +168,17 @@ class ToolsMenu(gtk.Menu):
window.show_all()
window.set_keep_above(True)
def enable_dependents(self):
"""
"""
self.__hosts.set_sensitive(True)
def disable_dependents(self):
"""
"""
self.__hosts.set_sensitive(False)
class Toolbar(gtk.HBox):
"""
"""
@@ -213,7 +207,6 @@ class Toolbar(gtk.HBox):
self.__create_widgets()
def __create_widgets(self):
"""
"""
@@ -233,7 +226,8 @@ class Toolbar(gtk.HBox):
self.__hosts_button = BWStockButton(gtk.STOCK_INDEX, _("Hosts Viewer"))
self.__hosts_button.connect("clicked", self.__hosts_viewer_callback)
self.__control = BWToggleStockButton(gtk.STOCK_PROPERTIES, _("Controls"))
self.__control = BWToggleStockButton(
gtk.STOCK_PROPERTIES, _("Controls"))
self.__control.connect('clicked', self.__control_callback)
self.__control.set_active(False)
@@ -273,7 +267,6 @@ class Toolbar(gtk.HBox):
self.pack_start(self.__control, False)
self.pack_end(self.__save_button, False)
def disable_controls(self):
"""
"""
@@ -282,7 +275,6 @@ class Toolbar(gtk.HBox):
self.__hosts_button.set_sensitive(False)
#self.__tools_menu.disable_dependents()
def enable_controls(self):
"""
"""
@@ -291,13 +283,11 @@ class Toolbar(gtk.HBox):
self.__hosts_button.set_sensitive(True)
#self.__tools_menu.enable_dependents()
def __tools_callback(self, widget):
"""
"""
self.__tools_menu.popup(None, None, None, 1, 0)
def __hosts_viewer_callback(self, widget):
"""
"""
@@ -305,7 +295,6 @@ class Toolbar(gtk.HBox):
window.show_all()
window.set_keep_above(True)
def __save_image_callback(self, widget):
"""
"""
@@ -330,7 +319,6 @@ class Toolbar(gtk.HBox):
self.__save_chooser.hide()
def __control_callback(self, widget=None):
"""
"""
@@ -340,7 +328,6 @@ class Toolbar(gtk.HBox):
else:
self.__control_widget.hide()
def __fisheye_callback(self, widget=None):
"""
"""
@@ -356,14 +343,12 @@ class Toolbar(gtk.HBox):
self.__fisheye_widget.deactive_fisheye()
self.__fisheye_widget.hide()
def __about_callback(self, widget):
"""
"""
self.__about_dialog = AboutDialog()
self.__about_dialog.show_all()
def __fullscreen_callback(self, widget=None):
"""
"""
@@ -372,4 +357,3 @@ class Toolbar(gtk.HBox):
else:
self.__window.unfullscreen()

View File

@@ -118,4 +118,3 @@
# * Nmap, and also available from https://svn.nmap.org/nmap/COPYING *
# * *
# ***************************************************************************/

View File

@@ -118,4 +118,3 @@
# * Nmap, and also available from https://svn.nmap.org/nmap/COPYING *
# * *
# ***************************************************************************/

View File

@@ -141,7 +141,7 @@ def is_in_circle(point, radius=1, center=(0, 0)):
x, y = point
a, b = center
if ((x - a)**2 + (y - b)**2) <= (radius**2):
if ((x - a) ** 2 + (y - b) ** 2) <= (radius ** 2):
return True
return False

View File

@@ -135,16 +135,17 @@ BASE_RADIUS = 5.5
NONE_RADIUS = 4.5
def set_node_info(node, host):
"""
"""
node.set_host(host)
radius = BASE_RADIUS + 2 * math.log(node.get_info("number_of_open_ports") + 1)
radius = BASE_RADIUS + 2 * math.log(
node.get_info("number_of_open_ports") + 1)
node.set_draw_info({"color": COLORS[node.get_info("vulnerability_score")],
"radius": radius})
node.set_draw_info({"color":COLORS[node.get_info("vulnerability_score")],
"radius":radius})
class TracerouteHostInfo(object):
"""This is a minimal implementation of HostInfo, sufficient to
@@ -164,15 +165,18 @@ class TracerouteHostInfo(object):
def get_best_osmatch(self):
if not self.osmatches:
return None
def osmatch_key(osmatch):
try:
return -float(osmatch["accuracy"])
except ValueError:
return 0
return sorted(self.osmatches, key = osmatch_key)[0]
return sorted(self.osmatches, key=osmatch_key)[0]
hostnames = property(lambda self: self.hostname and [self.hostname] or [])
def make_graph_from_hosts(hosts):
#hosts = parser.get_root().search_children('host', deep=True)
graph = Graph()
@@ -187,7 +191,8 @@ def make_graph_from_hosts(hosts):
localhost.ip = {"addr": "127.0.0.1/8", "type": "ipv4"}
localhost.hostname = "localhost"
main_node.set_host(localhost)
main_node.set_draw_info({"valid": True, "color":(0,0,0), "radius":NONE_RADIUS})
main_node.set_draw_info(
{"valid": True, "color": (0, 0, 0), "radius": NONE_RADIUS})
#Save endpoints for attaching scanned hosts to
endpoints = {}
@@ -219,10 +224,14 @@ def make_graph_from_hosts(hosts):
nodes.append(node)
hop_host = TracerouteHostInfo()
hop_host.ip = {"addr": hop["ipaddr"], "type": "", "vendor": ""}
node.set_draw_info({"valid":True})
node.set_draw_info({"color":(1,1,1),
"radius":NONE_RADIUS})
hop_host.ip = {
"addr": hop["ipaddr"],
"type": "",
"vendor": ""
}
node.set_draw_info({"valid": True})
node.set_draw_info({"color": (1, 1, 1),
"radius": NONE_RADIUS})
if hop["host"] != "":
hop_host.hostname = hop["host"]
@@ -240,8 +249,9 @@ def make_graph_from_hosts(hosts):
node = NetNode()
nodes.append(node)
node.set_draw_info({"valid":False})
node.set_draw_info({"color":(1,1,1), "radius":NONE_RADIUS})
node.set_draw_info({"valid": False})
node.set_draw_info(
{"color": (1, 1, 1), "radius": NONE_RADIUS})
graph.set_connection(node, prev_node)
@@ -259,12 +269,12 @@ def make_graph_from_hosts(hosts):
node = NetNode()
nodes.append(node)
node.set_draw_info({"no_route":True})
node.set_draw_info({"no_route": True})
graph.set_connection(node, endpoints[host])
node.set_draw_info({"valid":True})
node.set_draw_info({"scanned":True})
node.set_draw_info({"valid": True})
node.set_draw_info({"scanned": True})
set_node_info(node, host)
node_cache[node.get_info("ip")] = node

View File

@@ -124,7 +124,6 @@ from radialnet.util.geometry import *
import math
def ipv4_compare(ip1, ip2):
"""
"""
@@ -174,5 +173,7 @@ def sort_children_by_angle(children):
"""
vector = list(children)
vector.sort(key = lambda c: normalize_angle(c.get_draw_info('angle_from_father')))
vector.sort(
key=lambda c: normalize_angle(
c.get_draw_info('angle_from_father')))
return vector

View File

@@ -135,7 +135,8 @@ from glob import glob
from stat import *
from zenmapCore.Version import VERSION
from zenmapCore.Name import APP_NAME, APP_DISPLAY_NAME, APP_WEB_SITE, APP_DOWNLOAD_SITE, NMAP_DISPLAY_NAME
from zenmapCore.Name import APP_NAME, APP_DISPLAY_NAME, APP_WEB_SITE,\
APP_DOWNLOAD_SITE, NMAP_DISPLAY_NAME
# The name of the file used to record the list of installed files, so that the
# uninstall command can remove them.
@@ -154,6 +155,7 @@ misc_dir = os.path.join(data_dir, 'misc')
# Where to install .desktop files.
desktop_dir = os.path.join('share', 'applications')
def mo_find(result, dirname, fnames):
files = []
for f in fnames:
@@ -164,29 +166,31 @@ def mo_find(result, dirname, fnames):
if files:
result.append((dirname, files))
################################################################################
###############################################################################
# Installation variables
data_files = [ (pixmaps_dir, glob(os.path.join(pixmaps_dir, '*.gif')) +
glob(os.path.join(pixmaps_dir, '*.png'))),
data_files = [
(pixmaps_dir, glob(os.path.join(pixmaps_dir, '*.gif')) +
glob(os.path.join(pixmaps_dir, '*.png'))),
(os.path.join(pixmaps_dir, "radialnet"),
glob(os.path.join(pixmaps_dir, "radialnet", '*.png'))),
(os.path.join(pixmaps_dir, "radialnet"),
glob(os.path.join(pixmaps_dir, "radialnet", '*.png'))),
(config_dir, [os.path.join(config_dir, APP_NAME + '.conf')] +
[os.path.join(config_dir, 'scan_profile.usp')] +
[os.path.join(config_dir, APP_NAME + '_version')]),
(config_dir, [os.path.join(config_dir, APP_NAME + '.conf'),
os.path.join(config_dir, 'scan_profile.usp'),
os.path.join(config_dir, APP_NAME + '_version')]),
(misc_dir, glob(os.path.join(misc_dir, '*.xml'))),
(misc_dir, glob(os.path.join(misc_dir, '*.xml'))),
(docs_dir, [os.path.join(docs_dir, 'help.html')])]
(docs_dir, [os.path.join(docs_dir, 'help.html')])
]
# Add i18n files to data_files list
os.path.walk(locale_dir, mo_find, data_files)
# path_startswith and path_strip_prefix are used to deal with the installation
# root (--root option, also known as DESTDIR).
def path_startswith(path, prefix):
"""Returns True if path starts with prefix. It's a little more intelligent
than str.startswith because it normalizes the paths to remove multiple
@@ -195,10 +199,11 @@ def path_startswith(path, prefix):
prefix = os.path.normpath(prefix)
return path.startswith(prefix)
def path_strip_prefix(path, prefix):
"""Return path stripped of its directory prefix if it starts with prefix,
otherwise return path unmodified. This only works correctly with Unix paths;
for example it will not replace the drive letter on a Windows path.
otherwise return path unmodified. This only works correctly with Unix
paths; for example it will not replace the drive letter on a Windows path.
Examples:
>>> path_strip_prefix('/tmp/destdir/usr/bin', '/tmp/destdir')
'/usr/bin'
@@ -221,14 +226,16 @@ def path_strip_prefix(path, prefix):
assert os.path.isabs(path) == absolute
return path
################################################################################
###############################################################################
# Distutils subclasses
class my_install(install):
def finalize_options(self):
# Ubuntu's python2.6-2.6.4-0ubuntu3 package changes sys.prefix in
# install.finalize_options when sys.prefix is "/usr/local" (our
# default). Because we need the unchanged value later, remember it here.
# default). Because we need the unchanged value later, remember it
# here.
self.saved_prefix = self.prefix
install.finalize_options(self)
@@ -252,14 +259,17 @@ class my_install(install):
# Recursively include all the directories in data_dir (share/zenmap).
# This is mainly for convenience in listing locale directories.
installed_files.append(os.path.join(self.install_data, data_dir))
for dirpath, dirs, files in os.walk(os.path.join(self.install_data, data_dir)):
for dirpath, dirs, files in os.walk(
os.path.join(self.install_data, data_dir)):
for dir in dirs:
installed_files.append(os.path.join(dirpath, dir))
installed_files.append(os.path.join(self.install_scripts, "uninstall_" + APP_NAME))
installed_files.append(
os.path.join(self.install_scripts, "uninstall_" + APP_NAME))
return installed_files
def create_uninstaller(self):
uninstaller_filename = os.path.join(self.install_scripts, "uninstall_" + APP_NAME)
uninstaller_filename = os.path.join(
self.install_scripts, "uninstall_" + APP_NAME)
uninstaller = """\
#!/usr/bin/env python
@@ -267,26 +277,28 @@ import errno, os, os.path, sys
print 'Uninstall %(name)s %(version)s'
answer = raw_input('Are you sure that you want to uninstall %(name)s %(version)s? (yes/no) ')
answer = raw_input('Are you sure that you want to uninstall '
'%(name)s %(version)s? (yes/no) ')
if answer != 'yes' and answer != 'y':
print 'Not uninstalling.'
sys.exit(0)
""" % {'name':APP_DISPLAY_NAME, 'version':VERSION}
""" % {'name': APP_DISPLAY_NAME, 'version': VERSION}
installed_files = []
for output in self.get_installed_files():
if self.root is not None:
# If we have a root (DESTDIR), we need to strip it off the front
# of paths so the uninstaller runs on the target host. The path
# manipulations are tricky, but made easier because the
# uninstaller only has to run on Unix.
# If we have a root (DESTDIR), we need to strip it off the
# front of paths so the uninstaller runs on the target host.
# The path manipulations are tricky, but made easier because
# the uninstaller only has to run on Unix.
if not path_startswith(output, self.root):
# This should never happen (everything gets installed inside
# the root), but if it does, be safe and don't delete
# anything.
uninstaller += "print '%s was not installed inside the root %s; skipping.'\n" % (output, self.root)
# This should never happen (everything gets installed
# inside the root), but if it does, be safe and don't
# delete anything.
uninstaller += ("print '%s was not installed inside "
"the root %s; skipping.'\n" % (output, self.root))
continue
output = path_strip_prefix(output, self.root)
assert os.path.isabs(output)
@@ -356,7 +368,8 @@ for dir in dirs:
lines[i] = "INSTALL_LIB = %s\n" % repr(modules_dir)
break
else:
raise ValueError("INSTALL_LIB replacement not found in %s" % app_file_name)
raise ValueError(
"INSTALL_LIB replacement not found in %s" % app_file_name)
app_file = open(app_file_name, "w")
app_file.writelines(lines)
@@ -380,16 +393,17 @@ for dir in dirs:
S_IRGRP | \
S_IROTH)
def fix_paths(self):
"""Replace some hardcoded paths to match where files were installed."""
interesting_paths = {"CONFIG_DIR": os.path.join(self.saved_prefix, config_dir),
"DOCS_DIR": os.path.join(self.saved_prefix, docs_dir),
"LOCALE_DIR": os.path.join(self.saved_prefix, locale_dir),
"MISC_DIR": os.path.join(self.saved_prefix, misc_dir),
"PIXMAPS_DIR": os.path.join(self.saved_prefix, pixmaps_dir),
# See $(nmapdatadir) in nmap/Makefile.in.
"NMAPDATADIR": os.path.join(self.saved_prefix, "share", "nmap"),}
interesting_paths = {
"CONFIG_DIR": os.path.join(self.saved_prefix, config_dir),
"DOCS_DIR": os.path.join(self.saved_prefix, docs_dir),
"LOCALE_DIR": os.path.join(self.saved_prefix, locale_dir),
"MISC_DIR": os.path.join(self.saved_prefix, misc_dir),
"PIXMAPS_DIR": os.path.join(self.saved_prefix, pixmaps_dir),
# See $(nmapdatadir) in nmap/Makefile.in.
"NMAPDATADIR": os.path.join(self.saved_prefix, "share", "nmap")
}
# Find and read the Paths.py file.
pcontent = ""
@@ -417,8 +431,10 @@ for dir in dirs:
# Rewrite the zenmap.desktop and zenmap-root.desktop files to point to
# the installed locations of the su-to-zenmap.sh script and application
# icon.
su_filename = os.path.join(self.saved_prefix, data_dir, "su-to-zenmap.sh")
icon_filename = os.path.join(self.saved_prefix, pixmaps_dir, "zenmap.png")
su_filename = os.path.join(
self.saved_prefix, data_dir, "su-to-zenmap.sh")
icon_filename = os.path.join(
self.saved_prefix, pixmaps_dir, "zenmap.png")
desktop_filename = None
root_desktop_filename = None
@@ -442,7 +458,9 @@ for dir in dirs:
df = open(root_desktop_filename, "r")
dcontent = df.read()
df.close()
regex = re.compile("^((?:Exec|TryExec) *= *).*su-to-zenmap.sh(.*)$", re.MULTILINE)
regex = re.compile(
"^((?:Exec|TryExec) *= *).*su-to-zenmap.sh(.*)$",
re.MULTILINE)
dcontent = regex.sub("\\1%s\\2" % su_filename, dcontent)
regex = re.compile("^(Icon *= *).*$", re.MULTILINE)
dcontent = regex.sub("\\1%s" % icon_filename, dcontent)
@@ -456,7 +474,8 @@ for dir in dirs:
doesn't strip off the installation root, if any. File names containing
newline characters are not handled."""
if INSTALLED_FILES_NAME == self.record:
distutils.log.warn("warning: installation record is overwriting --record file '%s'." % self.record)
distutils.log.warn("warning: installation record is overwriting "
"--record file '%s'." % self.record)
f = open(INSTALLED_FILES_NAME, "w")
try:
for output in self.get_installed_files():
@@ -465,12 +484,14 @@ for dir in dirs:
finally:
f.close()
class my_uninstall(Command):
"""A distutils command that performs uninstallation. It reads the list of
installed files written by the install command."""
command_name = "uninstall"
description = "uninstall installed files recorded in '%s'" % INSTALLED_FILES_NAME
description = "uninstall installed files recorded in '%s'" % (
INSTALLED_FILES_NAME)
user_options = []
def initialize_options(self):
@@ -485,7 +506,8 @@ class my_uninstall(Command):
f = open(INSTALLED_FILES_NAME, "r")
except IOError, e:
if e.errno == errno.ENOENT:
log.error("Couldn't open the installation record '%s'. Have you installed yet?" % INSTALLED_FILES_NAME)
log.error("Couldn't open the installation record '%s'. "
"Have you installed yet?" % INSTALLED_FILES_NAME)
return
installed_files = [file.rstrip("\n") for file in f.readlines()]
f.close()
@@ -510,7 +532,7 @@ class my_uninstall(Command):
# Delete the directories. First reverse-sort the normalized paths by
# length so that child directories are deleted before their parents.
dirs = [os.path.normpath(dir) for dir in dirs]
dirs.sort(key = len, reverse = True)
dirs.sort(key=len, reverse=True)
for dir in dirs:
try:
log.info("Removing the directory '%s'." % dir)
@@ -523,8 +545,8 @@ class my_uninstall(Command):
log.error(str(e))
# setup can be called in different ways depending on what we're doing. (For
# example py2exe needs special handling.) These arguments are common between all
# the operations.
# example py2exe needs special handling.) These arguments are common between
# all the operations.
COMMON_SETUP_ARGS = {
'name': APP_NAME,
'license': 'Nmap License (http://nmap.org/book/man-legal.html)',
@@ -533,14 +555,14 @@ COMMON_SETUP_ARGS = {
'author': 'Nmap Project',
'maintainer': 'Nmap Project',
'description': "%s frontend and results viewer" % NMAP_DISPLAY_NAME,
'long_description': """\
%s is an %s frontend \
that is really useful for advanced users and easy to be used by newbies.""" \
% (APP_DISPLAY_NAME, NMAP_DISPLAY_NAME),
'long_description': "%s is an %s frontend that is really useful"
"for advanced users and easy to be used by newbies." % (
APP_DISPLAY_NAME, NMAP_DISPLAY_NAME),
'version': VERSION,
'scripts': [APP_NAME],
'packages': ['zenmapCore', 'zenmapGUI', 'zenmapGUI.higwidgets',
'radialnet', 'radialnet.bestwidgets', 'radialnet.core', 'radialnet.gui', 'radialnet.util'],
'radialnet', 'radialnet.bestwidgets', 'radialnet.core',
'radialnet.gui', 'radialnet.util'],
'data_files': data_files,
}
@@ -555,17 +577,24 @@ if 'py2exe' in sys.argv:
WINDOWS_SETUP_ARGS = {
'zipfile': 'py2exe/library.zip',
'name': APP_NAME,
'windows': [{"script": APP_NAME,
"icon_resources": [(1, "install_scripts/windows/nmap-eye.ico")]}],
'windows': [{
"script": APP_NAME,
"icon_resources": [(1, "install_scripts/windows/nmap-eye.ico")]
}],
# On Windows we build Ndiff here in Zenmap's setup.py so the two Python
# programs will share a common runtime.
'console': [{"script": "../ndiff/scripts/ndiff", "description": "Nmap scan comparison tool"}],
'console': [{
"script": "../ndiff/scripts/ndiff",
"description": "Nmap scan comparison tool"
}],
'options': {"py2exe": {
"compressed": 1,
"optimize": 2,
"packages": ["encodings"],
"includes": ["pango", "atk", "gobject", "gio", "pickle", "bz2", "encodings", "encodings.*", "cairo", "pangocairo"],
"dll_excludes": ["USP10.dll", "NSI.dll", "MSIMG32.dll", "DNSAPI.dll"]
"includes": ["pango", "atk", "gobject", "gio", "pickle", "bz2",
"encodings", "encodings.*", "cairo", "pangocairo"],
"dll_excludes": ["USP10.dll", "NSI.dll", "MSIMG32.dll",
"DNSAPI.dll"]
}
}
}

View File

@@ -127,7 +127,7 @@ import sys
# recursively checked, up to a limit of SYMLINK_LIMIT.
# https://www.securecoding.cert.org/confluence/display/seccode/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory
SYMLINK_LIMIT = 5
def is_secure_dir(path, num_symlinks = 0):
def is_secure_dir(path, num_symlinks=0):
import os
import os.path
import stat

View File

@@ -126,6 +126,7 @@ import sys
from zenmapCore.Name import APP_NAME
def fs_dec(s):
"""Decode s from the filesystem decoding, handling various possible
errors."""
@@ -134,6 +135,7 @@ def fs_dec(s):
enc = "UTF-8"
return s.decode(enc)
def fs_enc(u):
"""Encode u to the filesystem decoding, handling various possible
errors."""
@@ -146,20 +148,20 @@ def fs_enc(u):
# home directory, because os.path.expanduser doesn't properly decode the raw
# byte string from the file system encoding. You get a UnicodeDecodeError on
# systems like Windows where the file system encoding is different from the
# result of sys.getdefaultencoding(). So we call os.path.expanduser with a plain
# string and decode it from the filesystem encoding.
# result of sys.getdefaultencoding(). So we call os.path.expanduser with a
# plain string and decode it from the filesystem encoding.
HOME = fs_dec(os.path.expanduser("~"))
# The base_paths dict in this file gives symbolic names to various files. For
# example, use base_paths.target_list instead of 'target_list.txt'.
base_paths = dict(user_config_file = APP_NAME + '.conf',
user_config_dir = os.path.join(HOME, '.' + APP_NAME),
scan_profile = 'scan_profile.usp',
profile_editor = 'profile_editor.xml',
recent_scans = 'recent_scans.txt',
target_list = 'target_list.txt',
options = 'options.xml',
user_home = HOME,
db = APP_NAME + ".db",
version = APP_NAME + "_version")
base_paths = dict(user_config_file=APP_NAME + '.conf',
user_config_dir=os.path.join(HOME, '.' + APP_NAME),
scan_profile='scan_profile.usp',
profile_editor='profile_editor.xml',
recent_scans='recent_scans.txt',
target_list='target_list.txt',
options='options.xml',
user_home=HOME,
db=APP_NAME + ".db",
version=APP_NAME + "_version")

View File

@@ -136,9 +136,11 @@ import zenmapCore.Paths
# The [paths] configuration from zenmap.conf, used to get ndiff_command_path.
paths_config = PathsConfig()
class NdiffParseException(Exception):
pass
def get_path():
"""Return a value for the PATH environment variable that is appropriate
for the current platform. It will be the PATH from the environment plus
@@ -153,8 +155,9 @@ def get_path():
search_paths.append(path)
return os.pathsep.join(search_paths)
class NdiffCommand(subprocess.Popen):
def __init__(self, filename_a, filename_b, temporary_filenames = []):
def __init__(self, filename_a, filename_b, temporary_filenames=[]):
self.temporary_filenames = temporary_filenames
search_paths = get_path()
@@ -162,20 +165,38 @@ class NdiffCommand(subprocess.Popen):
env["PATH"] = search_paths
if getattr(sys, "frozen", None) == "macosx_app":
# These variables are set by py2app, but they can interfere with
# Ndiff because Ndiff is also a Python application. Without removing
# these, Ndiff will attempt to run using the py2app-bundled Python
# library, and may run into version or architecture mismatches.
if env.has_key("PYTHONPATH"):
# Ndiff because Ndiff is also a Python application. Without
# removing these, Ndiff will attempt to run using the
# py2app-bundled Python library, and may run into version or
# architecture mismatches.
if "PYTHONPATH" in env:
del env["PYTHONPATH"]
if env.has_key("PYTHONHOME"):
if "PYTHONHOME" in env:
del env["PYTHONHOME"]
command_list = [paths_config.ndiff_command_path, "--verbose", "--", filename_a, filename_b]
self.stdout_file = tempfile.TemporaryFile(mode = "rb", prefix = APP_NAME + "-ndiff-", suffix = ".xml")
command_list = [
paths_config.ndiff_command_path,
"--verbose",
"--",
filename_a,
filename_b
]
self.stdout_file = tempfile.TemporaryFile(
mode="rb",
prefix=APP_NAME + "-ndiff-",
suffix=".xml"
)
log.debug("Running command: %s" % repr(command_list))
# See zenmapCore.NmapCommand.py for an explanation of the shell argument.
subprocess.Popen.__init__(self, command_list, stdout = self.stdout_file, stderr = self.stdout_file, env = env, shell = (sys.platform == "win32"))
# shell argument explained in zenmapCore.NmapCommand.py
subprocess.Popen.__init__(
self,
command_list,
stdout=self.stdout_file,
stderr=self.stdout_file,
env=env,
shell=(sys.platform == "win32")
)
def get_scan_diff(self):
self.wait()
@@ -194,13 +215,17 @@ class NdiffCommand(subprocess.Popen):
def kill(self):
self.close()
def ndiff(scan_a, scan_b):
"""Run Ndiff on two scan results, which may be filenames or NmapParserSAX
objects, and return a running NdiffCommand object."""
temporary_filenames = []
if isinstance(scan_a, NmapParserSAX):
fd, filename_a = tempfile.mkstemp(prefix = APP_NAME + "-diff-", suffix = ".xml")
fd, filename_a = tempfile.mkstemp(
prefix=APP_NAME + "-diff-",
suffix=".xml"
)
temporary_filenames.append(filename_a)
f = os.fdopen(fd, "wb")
scan_a.write_xml(f)
@@ -209,7 +234,10 @@ def ndiff(scan_a, scan_b):
filename_a = scan_a
if isinstance(scan_b, NmapParserSAX):
fd, filename_b = tempfile.mkstemp(prefix = APP_NAME + "-diff-", suffix = ".xml")
fd, filename_b = tempfile.mkstemp(
prefix=APP_NAME + "-diff-",
suffix=".xml"
)
temporary_filenames.append(filename_b)
f = os.fdopen(fd, "wb")
scan_b.write_xml(f)

View File

@@ -126,6 +126,7 @@ import sys
from zenmapCore.Name import APP_NAME
def get_locales():
"""Get a list of locales to use based on system configuration."""
locales = []
@@ -148,6 +149,7 @@ def get_locales():
pass
return locales
def install_gettext(locale_dir):
try:
locale.setlocale(locale.LC_ALL, '')
@@ -162,8 +164,9 @@ def install_gettext(locale_dir):
except ImportError:
pass
else:
t = gettext.translation(APP_NAME, locale_dir, languages = get_locales(), fallback = True)
t.install(unicode = True)
t = gettext.translation(
APP_NAME, locale_dir, languages=get_locales(), fallback=True)
t.install(unicode=True)
# Install a dummy _ function so modules can safely use it after importing this
# module, even if they don't install the gettext version.

View File

@@ -122,11 +122,13 @@
import re
class NSEDocEvent (object):
def __init__(self, type, text = None):
def __init__(self, type, text=None):
self.type = type
self.text = text
def nsedoc_parse_sub(text, pos):
"""Parse paragraph-level NSEDoc markup, inside of paragraphs and lists.
Returns the position after the end of parsing followed by a list of
@@ -145,6 +147,7 @@ def nsedoc_parse_sub(text, pos):
return pos + m.end(), events
return pos, events
def nsedoc_parse(text):
"""Parse text marked up for NSEDoc. This is a generator that returns a
sequence of NSEDocEvents. The type of the event may be "paragraph_start",

View File

@@ -128,9 +128,11 @@ import zenmapCore.NmapParser
from zenmapGUI.SearchGUI import SearchParser
from SearchResult import HostSearch
class NetworkInventory(object):
"""This class acts as a container for aggregated scans. It is also
responsible for opening/saving the aggregation from/to persistent storage."""
responsible for opening/saving the aggregation from/to persistent
storage."""
def __init__(self, filename=None):
# A list of all scans that make up this inventory
self.scans = []
@@ -162,8 +164,8 @@ class NetworkInventory(object):
# Add this host to the hosts dictionary, mapped by IP address
self.hosts[addr] = host.make_clone()
else:
# This host is already present in the host list, so we need to update its
# info with the info held in the current host object
# This host is already present in the host list, so we need to
# update its info with the info held in the current host object
old_host = self.hosts[addr]
# We need to find old_host's scan date
old_date = localtime(0)
@@ -171,7 +173,8 @@ class NetworkInventory(object):
if old_host in old_scan.get_hosts():
old_date = old_scan.get_date()
new_date = scan.get_date()
self._update_host_info(old_host, host, old_date, new_date, scan)
self._update_host_info(
old_host, host, old_date, new_date, scan)
self.scans.append(scan)
@@ -179,7 +182,8 @@ class NetworkInventory(object):
basename = os.path.basename(filename)
if basename in self.filenames.values():
# We need to generate a new filename, since this basename already exists
# We need to generate a new filename, since this basename
# already exists
base = basename
ext = "xml"
try:
@@ -195,7 +199,8 @@ class NetworkInventory(object):
self.filenames[scan] = basename
def remove_scan(self, scan):
"""Removes a scan and any host information it contained from the inventory."""
"""Removes a scan and any host information it contained from the
inventory."""
# Note: If a scan is passed in that isn't in the inventory then this
# method will throw a ValueError Exception and will not finish
# Remove the scan from our scan list
@@ -214,12 +219,13 @@ class NetworkInventory(object):
if scan in self.filenames:
del self.filenames[scan]
# For each scan in the remembered list, append it to the scan list and update
# the host list accordingly
# For each scan in the remembered list, append it to the scan list and
# update the host list accordingly
for scan in scans:
self.add_scan(scan)
def _update_host_info(self, old_host, new_host, old_date, new_date, new_scan):
def _update_host_info(self, old_host, new_host,
old_date, new_date, new_scan):
"""This function is called when a host needs to be added to the hosts
dictionary, but another HostInfo object for that host already exists
in the dictionary (from a previous scan). In that case, we need to
@@ -232,19 +238,21 @@ class NetworkInventory(object):
for new_port in new_host.ports:
# Check if new_port is already present in old_host's ports
for old_port in old_host.ports:
if old_port["portid"] == new_port["portid"] and old_port["protocol"] == new_port["protocol"]:
if (old_port["portid"] == new_port["portid"] and
old_port["protocol"] == new_port["protocol"]):
old_list.remove(old_port)
# We update old_host's port information to reflect the latest known port state
# We update old_host's port information to reflect the
# latest known port state
if old_date < new_date:
index = old_host.ports.index(old_port)
old_host.ports[index] = new_port
# Finished processing this new_port, we jump to the next one
# Finished processing this new_port, we jump to the next
break
else:
# This new_port isn't present in old_host, so we simply append it to
# old_host's port info
# This new_port isn't present in old_host, so we simply append
# it to old_host's port info
old_host.ports.append(new_port)
ports = new_scan.get_port_protocol_dict()
#remove ports which are no longer up
@@ -269,7 +277,8 @@ class NetworkInventory(object):
if old_host.comment == "":
old_host.comment = new_host.comment
elif new_host.comment != "":
old_host.comment = "%s\n\n%s" % (old_host.comment, new_host.comment)
old_host.comment = "%s\n\n%s" % (
old_host.comment, new_host.comment)
# Hostnames
# Replace old_host's hostname with new_host's if old_host has no
@@ -279,21 +288,29 @@ class NetworkInventory(object):
old_host.hostnames = new_host.hostnames
# MAC address
# If there was no MAC address set in old_host, set it to whatever is in new_host.mac.
# Do the same if both hosts have a MAC address set, but new_host's address is newer.
if old_host.mac is None or \
(old_host.mac is not None and new_host.mac is not None and old_date < new_date):
# If there was no MAC address set in old_host, set it to whatever is in
# new_host.mac. Do the same if both hosts have a MAC address set, but
# new_host's address is newer.
if (old_host.mac is None or
(old_host.mac is not None and
new_host.mac is not None and
old_date < new_date)
):
old_host.mac = new_host.mac
# OS detection fields
# Replace old_host's OS detection fields with new_host's if old_host has no
# OS detection info or new_host's info is newer.
if len(new_host.osmatches) > 0 and (len(old_host.osmatches) == 0 or old_date < new_date):
# Replace old_host's OS detection fields with new_host's if old_host
# has no OS detection info or new_host's info is newer.
if (len(new_host.osmatches) > 0 and
(len(old_host.osmatches) == 0 or old_date < new_date)
):
old_host.osmatches = new_host.osmatches
old_host.ports_used = new_host.ports_used
# Traceroute information
if len(new_host.trace) > 0 and (len(old_host.trace) == 0 or old_date < new_date):
if (len(new_host.trace) > 0 and
(len(old_host.trace) == 0 or old_date < new_date)
):
old_host.trace = new_host.trace
def get_scans(self):
@@ -317,7 +334,8 @@ class NetworkInventory(object):
self.add_scan(parsed, path)
def open_from_dir(self, path):
"""Loads all scans from the given directory into the network inventory."""
"""Loads all scans from the given directory into the network
inventory."""
from zenmapCore.NmapParser import NmapParser
for filename in os.listdir(path):
@@ -328,7 +346,7 @@ class NetworkInventory(object):
parsed.parse_file(fullpath)
self.add_scan(parsed, filename=fullpath)
def save_to_file(self, path, index, format = "xml"):
def save_to_file(self, path, index, format="xml"):
"""Saves the scan with the given list index into a file with a given
path. With format = "xml", saves Nmap XML; otherwise saves plain text
output."""
@@ -341,21 +359,24 @@ class NetworkInventory(object):
f.close()
def _generate_filenames(self, path):
"""Generates filenames for all scans that don't already have a filename."""
# The directory must not contain filenames other than those in the self.filenames dictionary
"""Generates filenames for all scans that don't already have a
filename."""
# The directory must not contain filenames other than those in the
# self.filenames dictionary
for filename in os.listdir(path):
if os.path.basename(filename) not in self.filenames.values():
raise Exception("The destination directory contains a file (%s) that's not a part "
"of the current inventory. The inventory will not be saved." %
os.path.basename(filename))
raise Exception("The destination directory contains a file"
"(%s) that's not a part of the current inventory."
"The inventory will not be saved." %
os.path.basename(filename))
for scan in self.scans:
if scan in self.filenames:
# This scan already has a filename
continue
date = "%04d%02d%02d%02d%02d" % (scan.date[0], scan.date[1], scan.date[2],
scan.date[3], scan.date[4])
date = "%04d%02d%02d%02d%02d" % (scan.date[0], scan.date[1],
scan.date[2], scan.date[3], scan.date[4])
filename = scan.get_scan_name()
# Prepend the date
@@ -367,20 +388,22 @@ class NetworkInventory(object):
filename = filename.replace(char, "_")
# Filename length check
# (http://en.wikipedia.org/wiki/Filename#Comparison_of_file_name_limitations)
# https://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits
if len(filename) > 250:
filename = filename[:250]
# TODO: Filename security checks?
# Try to open the file in append mode. If file.tell() returns a greater-than-zero
# value, this means that the file already exists and has some data in it, so we
# choose another filename until we successfully open a zero-length file.
# Try to open the file in append mode. If file.tell() returns a
# greater-than-zero value, this means that the file already exists
# and has some data in it, so we choose another filename until we
# successfully open a zero-length file.
filename_full = filename + ".xml"
counter = 2
while filename_full in self.filenames.values():
# There's already a scan with this filename, so we generate a new name by appending
# the counter value before the file extension.
# There's already a scan with this filename, so we generate a
# new name by appending the counter value before the file
# extension.
filename_full = "%s %s.xml" % (filename, str(counter))
counter += 1
@@ -413,12 +436,13 @@ class NetworkInventory(object):
f = StringIO()
parsed.write_xml(f)
scan = Scans(scan_name = parsed.scan_name,
nmap_xml_output = f.getvalue(),
date = time())
scan = Scans(scan_name=parsed.scan_name,
nmap_xml_output=f.getvalue(),
date=time())
class FilteredNetworkInventory(NetworkInventory):
def __init__(self, filename = None):
def __init__(self, filename=None):
NetworkInventory.__init__(self, filename)
# A dictionary listing host filtering criteria
@@ -459,18 +483,24 @@ class FilteredNetworkInventory(NetworkInventory):
return self.filtered_hosts
else:
return NetworkInventory.get_hosts(self)
def get_hosts_up(self):
if len(self.search_dict) > 0:
return filter(lambda h: h.get_state() == 'up', self.filtered_hosts)
return filter(lambda h: h.get_state() == 'up',
self.filtered_hosts)
else:
return NetworkInventory.get_hosts_up(self)
def get_hosts_down(self):
if len(self.search_dict) > 0:
return filter(lambda h: h.get_state() == 'down', self.filtered_hosts)
return filter(lambda h: h.get_state() == 'down',
self.filtered_hosts)
else:
return NetworkInventory.get_hosts_down(self)
def get_total_host_count(self):
return len(self.hosts)
def _match_all_args(self, host, operator, args):
"""A helper function that calls the matching function for the given
operator and each of its arguments."""
@@ -479,48 +509,63 @@ class FilteredNetworkInventory(NetworkInventory):
if arg != "" and arg[0] == "!":
arg = arg[1:]
positive = False
if positive != self.__getattribute__("match_%s" % operator)(host, arg):
if positive != self.__getattribute__(
"match_%s" % operator)(host, arg):
# No match for this operator
return False
else:
# if the operator is not supported, pretend its true
# All arguments for this operator produced a match
return True
def get_host_count(self):
return len(self.network_inventory.hosts)
def match_keyword(self, host, keyword):
return self.match_os(host, keyword) or\
self.match_target(host, keyword) or\
self.match_service(host, keyword)
def match_target(self, host, name):
return HostSearch.match_target(host, name)
def match_in_route(self, host, hop):
hops = host.get_trace().get('hops', [])
return hop in hops
def match_hostname(self, host, hostname):
return HostSearch.match_hostname(host, hostname)
def match_service(self, host, service):
return HostSearch.match_service(host, service)
def match_os(self, host, os):
return HostSearch.match_os(host, os)
def match_open(self, host, portno):
host_ports = host.get_ports()
return HostSearch.match_port(host_ports, portno, "open")
def match_closed(self, host, portno):
host_ports = host.get_ports()
return HostSearch.match_port(host_ports, portno, "closed")
def match_filtered(self, host, portno):
host_ports = host.get_ports()
return HostSearch.match_port(host_ports, portno, "filtered")
def match_unfiltered(self, host, portno):
host_ports = host.get_ports()
return HostSearch.match_port(host_ports, portno, "unfiltered")
def match_open_filtered(self, host, portno):
host_ports = host.get_ports()
return HostSearch.match_port(host_ports, portno, "open|filtered")
def match_closed_filtered(self, host, portno):
host_ports = host.get_ports()
return HostSearch.match_port(host_ports, portno, "closed|filtered")
def apply_filter(self, filter_text):
self.filter_text = filter_text.lower()
self.search_parser.update(self.filter_text)
@@ -537,10 +582,11 @@ class FilteredNetworkInventory(NetworkInventory):
# host satisfies all conditions
self.filtered_hosts.append(host)
class NetworkInventoryTest(unittest.TestCase):
def test_no_external_modification(self):
"""Test that HostInfo objects passed into the inventory are not modified
during aggregation."""
"""Test that HostInfo objects passed into the inventory are not
modified during aggregation."""
scan_1 = zenmapCore.NmapParser.ParserBasics()
host_a = zenmapCore.NmapParser.HostInfo()
host_a.hostnames = ["a"]
@@ -564,28 +610,30 @@ class NetworkInventoryTest(unittest.TestCase):
self.assertEqual(scan_1.nmap["hosts"], [host_a])
self.assertEqual(scan_2.nmap["hosts"], [host_b])
self.assertEqual(inv.get_hosts_up()[0].hostnames, ["b"])
def test_cancel_and_remove_scan(self):
"""Test that canceling and removing a scan does not blow away the inventory hosts"""
added_ips = ['10.0.0.1','10.0.0.2']
"""Test that canceling and removing a scan does not blow away the
inventory hosts"""
added_ips = ['10.0.0.1', '10.0.0.2']
removed_ips = ['10.0.0.3']
scan_1 = zenmapCore.NmapParser.ParserBasics()
host_a = zenmapCore.NmapParser.HostInfo()
host_a.hostnames = ["a"]
host_a.set_ip({'addr':added_ips[0]})
host_a.set_ip({'addr': added_ips[0]})
scan_1.start = "1000000000"
scan_1.nmap["hosts"] = [host_a]
scan_2 = zenmapCore.NmapParser.ParserBasics()
host_b = zenmapCore.NmapParser.HostInfo()
host_b.hostnames = ["b"]
host_b.set_ip({'addr':added_ips[1]})
host_b.set_ip({'addr': added_ips[1]})
scan_2.start = "1000000001"
scan_2.nmap["hosts"] = [host_b]
scan_3 = zenmapCore.NmapParser.ParserBasics()
host_c = zenmapCore.NmapParser.HostInfo()
host_c.hostnames = ["b"]
host_c.set_ip({'addr':removed_ips[0]})
host_c.set_ip({'addr': removed_ips[0]})
scan_3.start = "1000000001"
scan_3.nmap["hosts"] = [host_c]
@@ -600,6 +648,7 @@ class NetworkInventoryTest(unittest.TestCase):
self.assertEqual(host_a.hostnames, ["a"])
self.assertEqual(host_b.hostnames, ["b"])
class FilteredNetworkInventoryTest(unittest.TestCase):
def test_filter(self):
"""Test that the filter still works after moving code to the """
@@ -613,6 +662,7 @@ class FilteredNetworkInventoryTest(unittest.TestCase):
inv.apply_filter(filter_text)
assert(len(inv.get_hosts()) == 2)
class PortChangeTest(unittest.TestCase):
def test_port(self):
"""Verify that the port status (open/filtered/closed) is diplayed """ \
@@ -632,17 +682,17 @@ class PortChangeTest(unittest.TestCase):
assert(len(inv.get_hosts()[0].ports) == 0)
# Additional test case for when the two scans have port scan ranges
# which do not overlap. Example nmap -F -sU versus
# nmap -F scanme.nmap.org
# which do not overlap. Example nmap -F -sU versus
# nmap -F scanme.nmap.org
inv = NetworkInventory()
scan4 = NmapParser()
scan4.parse_file("test/xml_test16.xml")
inv.add_scan(scan4)
assert(len(inv.get_hosts()[0].ports)==3)
assert(len(inv.get_hosts()[0].ports) == 3)
scan5 = NmapParser()
scan5.parse_file("test/xml_test17.xml")
inv.add_scan(scan5)
assert(len(inv.get_hosts()[0].ports)==7)
assert(len(inv.get_hosts()[0].ports) == 7)
if __name__ == "__main__":
unittest.main()

View File

@@ -152,6 +152,7 @@ paths_config = PathsConfig()
log.debug(">>> Platform: %s" % sys.platform)
def wrap_file_in_preferred_encoding(f):
"""Wrap an open file to automatically decode its contents when reading from
the encoding given by locale.getpreferredencoding, or just return the file
@@ -184,17 +185,19 @@ def wrap_file_in_preferred_encoding(f):
return f
def escape_nmap_filename(filename):
"""Escape '%' characters so they are not interpreted as strftime format
specifiers, which are not supported by Zenmap."""
return filename.replace("%", "%%")
class NmapCommand(object):
"""This class represents an Nmap command line. It is responsible for
starting, stopping, and returning the results from a command-line scan. A
command line is represented as a string but it is split into a list of
arguments for execution.
The normal output (stdout and stderr) are written to the file object
self.stdout_file."""
@@ -231,7 +234,8 @@ class NmapCommand(object):
self.ops[op] = escape_nmap_filename(self.ops[op])
if self.xml_is_temp:
self.xml_output_filename = tempfile.mktemp(prefix = APP_NAME + "-", suffix = ".xml")
self.xml_output_filename = tempfile.mktemp(
prefix=APP_NAME + "-", suffix=".xml")
self.ops["-oX"] = escape_nmap_filename(self.xml_output_filename)
log.debug(">>> Temporary files:")
@@ -261,7 +265,8 @@ class NmapCommand(object):
else:
try:
import ctypes
ctypes.windll.kernel32.TerminateProcess(int(self.command_process._handle), -1)
ctypes.windll.kernel32.TerminateProcess(
int(self.command_process._handle), -1)
except:
pass
@@ -279,13 +284,13 @@ class NmapCommand(object):
search_paths.append(path)
return os.pathsep.join(search_paths)
def run_scan(self, stderr = None):
def run_scan(self, stderr=None):
"""Run the command represented by this class."""
# We don't need a file name for stdout output, just a handle. A
# TemporaryFile is deleted as soon as it is closed, and in Unix is
# unlinked immediately after creation so it's not even visible.
f = tempfile.TemporaryFile(mode = "rb", prefix = APP_NAME + "-stdout-")
f = tempfile.TemporaryFile(mode="rb", prefix=APP_NAME + "-stdout-")
self.stdout_file = wrap_file_in_preferred_encoding(f)
if stderr is None:
stderr = f
@@ -303,7 +308,8 @@ class NmapCommand(object):
# This keeps a terminal window from opening.
startupinfo = subprocess.STARTUPINFO()
try:
startupinfo.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW
startupinfo.dwFlags |= \
subprocess._subprocess.STARTF_USESHOWWINDOW
except AttributeError:
# This name is used before Python 2.6.5.
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
@@ -312,7 +318,7 @@ class NmapCommand(object):
stdin=subprocess.PIPE,
stdout=f,
stderr=stderr,
startupinfo = startupinfo,
startupinfo=startupinfo,
env=env)
def scan_state(self):
@@ -327,15 +333,18 @@ class NmapCommand(object):
state = self.command_process.poll()
if state == None:
return True # True means that the process is still running
return True # True means that the process is still running
elif state == 0:
return False # False means that the process had a successful exit
return False # False means that the process had a successful exit
else:
log.warning("An error occurred during the scan execution!")
log.warning("Command that raised the exception: '%s'" % self.ops.render_string())
log.warning("Command that raised the exception: '%s'" %
self.ops.render_string())
log.warning("Scan output:\n%s" % self.get_output())
raise Exception("An error occurred during the scan execution!\n\n'%s'" % self.get_output())
raise Exception(
"An error occurred during the scan execution!\n\n'%s'" %
self.get_output())
def get_output(self):
"""Return the complete contents of the self.stdout_file. This modifies
@@ -348,4 +357,5 @@ class NmapCommand(object):
return self.xml_output_filename
if __name__ == '__main__':
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(SplitQuotedTest))
unittest.TextTestRunner().run(
unittest.TestLoader().loadTestsFromTestCase(SplitQuotedTest))

View File

@@ -2,8 +2,8 @@
# This is an Nmap command line parser. It has two main parts:
#
# getopt_long_only_extras, which is like getopt_long_only with robust handling
# of unknown options.
# getopt_long_only_extras, which is like getopt_long_only with robust
# handling of unknown options.
#
# NmapOptions, a class representing a set of Nmap options.
#
@@ -30,9 +30,11 @@
# >>> ops["-v"] = 2
# >>> ops["-oX"] = "output.xml"
# >>> ops.render()
# ['C:\\Program Files\\Nmap\\nmap.exe', '-v', '-v', '-oX', 'output.xml', '--script', 'safe', 'localhost']
# ['C:\\Program Files\\Nmap\\nmap.exe', '-v', '-v', '-oX', 'output.xml',
# '--script', 'safe', 'localhost']
# >>> ops.render_string()
# '"C:\\Program Files\\Nmap\\nmap.exe" -v -v -oX output.xml --script safe localhost'
# '"C:\\Program Files\\Nmap\\nmap.exe" -v -v -oX output.xml\
# --script safe localhost'
#
# A primary design consideration was robust handling of unknown options. That
# gives this code a degree of independence from Nmap's own list of options. If
@@ -45,17 +47,17 @@
# nmap -x -e eth0 scanme.nmap.org
# If -x, whatever it is, does not take an argument, it is equivalent to
# nmap -e eth0 scanme.nmap.org -x
# that is, a scan of scanme.nmap.org over interface eth0. But if it does take an
# argument, its argument is "-e", and the command line is the same as
# that is, a scan of scanme.nmap.org over interface eth0. But if it does take
# an argument, its argument is "-e", and the command line is the same as
# nmap eth0 scanme.nmap.org -x -e
# which is a scan of the two hosts eth0 and scanme.nmap.org, over the default
# interface. In either case scanme.nmap.org is a target but the other arguments
# are ambiguous. To resolve this, once an unknown option is found, all following
# arguments that can be interpreted ambiguously are removed with it and placed
# in the extras, with normal option processing resumed only when there is no
# more ambiguity. This ensures that such options maintain their relative order
# when rendered again to output. In this example "-x -e eth0" will always appear
# in that order, and the -e option will be uninterpreted.
# are ambiguous. To resolve this, once an unknown option is found, all
# following arguments that can be interpreted ambiguously are removed with it
# and placed in the extras, with normal option processing resumed only when
# there is no more ambiguity. This ensures that such options maintain their
# relative order when rendered again to output. In this example "-x -e eth0"
# will always appear in that order, and the -e option will be uninterpreted.
#
# To add a new option, one should do the following:
# 1) Add a test case to the NmapOptionsTest::test_options() method for the new
@@ -79,6 +81,7 @@
# get_option_check_auxiliary_widget in OptionBuilder.py.
# 7) Make sure the test case works now.
class option:
"""A single option, part of a pool of potential options. It's just a name
and a flag saying if the option takes no argument, if an agument is
@@ -91,6 +94,7 @@ class option:
self.name = name
self.has_arg = has_arg
def split_quoted(s):
"""Like str.split, except that no splits occur inside quoted strings, and
quoted strings are unquoted."""
@@ -114,8 +118,8 @@ def split_quoted(s):
i += 1
if i < len(s):
c = s[i]
# Otherwise, ignore the error and leave the backslash at
# the end of the string.
# Otherwise, ignore the error and leave the backslash
# at the end of the string.
part.append(c)
i += 1
else:
@@ -127,6 +131,7 @@ def split_quoted(s):
return r
def maybe_quote(s):
"""Return s quoted if it needs to be, otherwise unchanged."""
for c in s:
@@ -146,9 +151,11 @@ def maybe_quote(s):
return "\"" + "".join(r) + "\""
def join_quoted(l):
return " ".join([maybe_quote(x) for x in l])
def make_options(short_opts, long_opts):
"""Parse a short option specification string and long option tuples into a
list of option objects."""
@@ -176,6 +183,7 @@ def make_options(short_opts, long_opts):
lookup_option_cache = {}
def lookup_option(name, options):
"""Find an option with the given (possibly abbreviated) name. None is
returned if no options match or if the name is ambiguous (more than one
@@ -197,7 +205,8 @@ def lookup_option(name, options):
return name.replace("_", "-")
name = canonicalize_name(name)
matches = [o for o in options if canonicalize_name(o.name).startswith(name)]
matches = [o for o in options
if canonicalize_name(o.name).startswith(name)]
if len(matches) == 0:
# No match.
lookup_option_cache[cache_code] = None
@@ -215,19 +224,22 @@ def lookup_option(name, options):
lookup_option_cache[cache_code] = None
return lookup_option_cache[cache_code]
def split_option(cmd_arg, options):
"""Split an option into a name, argument (if any), and possible remainder.
It is not an error if the option does not include an argument even though it
is required; the caller must take the argument from the next command-line
argument. The remainder is what's left over after stripping a single short
option that doesn't take an argument. At most one of argument and remainder
will be non-None.
It is not an error if the option does not include an argument even though
it is required; the caller must take the argument from the next
command-line argument. The remainder is what's left over after stripping a
single short option that doesn't take an argument. At most one of argument
and remainder will be non-None.
Examples:
>>> split_option("-v", [option("v", option.NO_ARGUMENT)])
('v', None, None)
>>> split_option("--min-rate", [option("min-rate", option.REQUIRED_ARGUMENT)])
>>> split_option("--min-rate",
... [option("min-rate", option.REQUIRED_ARGUMENT)])
('min-rate', None, None)
>>> split_option("--min-rate=100", [option("min-rate", option.REQUIRED_ARGUMENT)])
>>> split_option("--min-rate=100",
... [option("min-rate", option.REQUIRED_ARGUMENT)])
('min-rate', '100', None)
>>> split_option("-d9", [option("d", option.OPTIONAL_ARGUMENT)])
('d', '9', None)
@@ -273,15 +285,17 @@ def split_option(cmd_arg, options):
else:
assert False, cmd_arg
def get_option(cmd_args, options):
"""Find and return the first option (plus a possible option argument) or
positional argument from the command-line option list in cmd_args. The
return value will have one of the following forms:
a string, representing a positional argument;
an (option, argument) pair (argument may be None);
a (None, extra, ...) tuple, where extra, ... is a chain of an unknown option
and its following arguments that cannot be interpreted unambiguously; or
None, at the end of the option list."""
* a string, representing a positional argument;
* an (option, argument) pair (argument may be None);
* a (None, extra, ...) tuple, where extra, ... is a chain of an unknown
option and its following arguments that cannot be interpreted
unambiguously; or
* None, at the end of the option list."""
if len(cmd_args) == 0:
return None
cmd_arg = cmd_args.pop(0)
@@ -305,9 +319,9 @@ def get_option(cmd_args, options):
return (None, cmd_arg)
else:
extras = [None, cmd_arg]
# We found an unknown option but we have a problem--we don't know if
# it takes an argument or not. So what we do is, we simulate what
# would happen both if the option took and argument and if it
# We found an unknown option but we have a problem--we don't know
# if it takes an argument or not. So what we do is, we simulate
# what would happen both if the option took and argument and if it
# didn't. The sync function does that by calling this function in a
# loop.
rest = sync(cmd_args[1:], cmd_args[:], options)
@@ -332,6 +346,7 @@ def get_option(cmd_args, options):
else:
return (option.name, arg)
def sync(a, b, options):
"""Given two command-line argument lists, incrementally get an option from
whichever is longer until both lists are equal. Return the resulting
@@ -343,15 +358,17 @@ def sync(a, b, options):
get_option(b, options)
return a
def getopt_long_only_extras(cmd_args, short_opts, long_opts):
"""This is a generator version of getopt_long_only that additionally has
robust handling of unknown options. Each of the items in the sequence it
yields will be one of the following:
a string, representing a positional argument;
an (option, argument) pair (argument may be None);
a (None, extra, ...) tuple, where extra, ... is a chain of an unknown option
and its following arguments that cannot be interpreted unambiguously; or
None, at the end of the option list."""
* a string, representing a positional argument;
* an (option, argument) pair (argument may be None);
* a (None, extra, ...) tuple, where extra, ... is a chain of an unknown
option and its following arguments that cannot be interpreted
unambiguously; or
* None, at the end of the option list."""
options = make_options(short_opts, long_opts)
# get_option modifies its list of arguments in place. Don't modify the
# original list.
@@ -362,6 +379,7 @@ def getopt_long_only_extras(cmd_args, short_opts, long_opts):
break
yield result
class NmapOptions(object):
SHORT_OPTIONS = "6Ab:D:d::e:Ffg:hi:M:m:nO::o:P:p:RrS:s:T:v::V"
LONG_OPTIONS = (
@@ -492,7 +510,8 @@ class NmapOptions(object):
def _set_executable(self, executable):
self._executable = executable
executable = property(lambda self: self._executable or "nmap", _set_executable)
executable = property(lambda self: self._executable or "nmap",
_set_executable)
def canonicalize_name(self, name):
opt, arg, remainder = split_option(name, self.options)
@@ -563,7 +582,8 @@ class NmapOptions(object):
"webxml",
):
self["--" + opt] = True
elif opt in ("b", "D", "e", "g", "i", "iL", "m", "M", "o", "oA", "oG", "oM", "oN", "oS", "oX", "p", "S", "sI"):
elif opt in ("b", "D", "e", "g", "i", "iL", "m", "M", "o", "oA", "oG",
"oM", "oN", "oS", "oX", "p", "S", "sI"):
assert arg is not None
if self["-" + opt] is None:
self["-" + opt] = arg
@@ -617,7 +637,8 @@ class NmapOptions(object):
try:
self["-d"] = int(arg)
except ValueError:
if reduce(lambda x, y: x and y, map(lambda z: z == "d", arg), True):
if reduce(lambda x, y: x and y,
map(lambda z: z == "d", arg), True):
self.setdefault("-d", 0)
self["-d"] += len(arg) + 1
else:
@@ -646,7 +667,8 @@ class NmapOptions(object):
self.extras.append("-O%s" % arg)
elif opt == "P":
type, ports = arg[:1], arg[1:]
if type == "0" or type == "D" or type == "N" or type == "n" and ports == "":
if (type == "0" or type == "D" or type == "N" or
type == "n" and ports == ""):
self["-Pn"] = True
elif (type == "" or type == "I" or type == "E") and ports == "":
self["-PE"] = True
@@ -693,7 +715,8 @@ class NmapOptions(object):
try:
self["-v"] = int(arg)
except ValueError:
if reduce(lambda x, y: x and y, map(lambda z: z == "v", arg), True):
if reduce(lambda x, y: x and y,
map(lambda z: z == "v", arg), True):
self.setdefault("-v", 0)
self["-v"] += len(arg) + 1
else:
@@ -707,7 +730,8 @@ class NmapOptions(object):
if len(opt_list) > 0:
self.executable = opt_list[0]
for result in getopt_long_only_extras(opt_list[1:], self.SHORT_OPTIONS, self.LONG_OPTIONS):
for result in getopt_long_only_extras(
opt_list[1:], self.SHORT_OPTIONS, self.LONG_OPTIONS):
self.handle_result(result)
def parse_string(self, opt_string):
@@ -716,7 +740,8 @@ class NmapOptions(object):
def render(self):
opt_list = []
for opt in ("-sA", "-sC", "-sF", "-sL", "-sM", "-sN", "-sO", "-sn", "-sR", "-sS", "-sT", "-sU", "-sV", "-sW", "-sX", "-sY", "-sZ"):
for opt in ("-sA", "-sC", "-sF", "-sL", "-sM", "-sN", "-sO", "-sn",
"-sR", "-sS", "-sT", "-sU", "-sV", "-sW", "-sX", "-sY", "-sZ"):
if self[opt]:
opt_list.append(opt)
@@ -865,6 +890,7 @@ class NmapOptions(object):
import doctest
import unittest
class NmapOptionsTest(unittest.TestCase):
def test_clear(self):
"""Test that a new object starts without defining any options, that the
@@ -901,7 +927,8 @@ class NmapOptionsTest(unittest.TestCase):
TEST = "nmap -T4 -A -v localhost --webxml"
ops = NmapOptions()
ops.parse_string(TEST)
self.assertTrue(type(ops.render()) == list, "type == %s" % type(ops.render))
self.assertTrue(type(ops.render()) == list,
"type == %s" % type(ops.render))
def test_quoted(self):
"""Test that strings can be quoted."""
@@ -1123,7 +1150,8 @@ class NmapOptionsTest(unittest.TestCase):
ops.parse_string("nmap -min-rate=100")
self.assertTrue(ops["--min-rate"] == "100")
# Short options not taking an argument can be followed by a long option.
# Short options not taking an argument can be followed by a long
# option.
ops.parse_string("nmap -nFmin-rate 100")
self.assertTrue(ops["-n"])
self.assertTrue(ops["-F"])
@@ -1155,8 +1183,8 @@ class NmapOptionsTest(unittest.TestCase):
self.assertEqual(ops["--nonoption"], None)
def test_canonical_option_names(self):
"""Test that equivalent option names are properly canonicalized, so that
ops["--timing"] and ops["-T"] mean the same thing, for example."""
"""Test that equivalent option names are properly canonicalized, so
that ops["--timing"] and ops["-T"] mean the same thing, for example."""
EQUIVS = (
("--debug", "-d"),
("--help", "-h"),
@@ -1334,11 +1362,17 @@ class NmapOptionsTest(unittest.TestCase):
ops.parse_string("nmap " + test)
opt_list_1 = ops.render()
self.assertTrue(len(opt_list_1) > 1, "%s missing on render" % test)
self.assertTrue(len(ops.extras) == 0, "%s caused extras: %s" % (test, repr(ops.extras)))
self.assertTrue(len(ops.extras) == 0,
"%s caused extras: %s" % (test, repr(ops.extras)))
ops.parse(opt_list_1)
opt_list_2 = ops.render()
self.assertTrue(opt_list_1 == opt_list_2, "Result of parsing and rendering %s not parsable again" % test)
self.assertTrue(len(ops.extras) == 0, "Result of parsing and rendering %s left extras: %s" % (test, ops.extras))
self.assertTrue(opt_list_1 == opt_list_2,
"Result of parsing and rendering %s not parsable again" % (
test))
self.assertTrue(len(ops.extras) == 0,
"Result of parsing and rendering %s left extras: %s" % (
test, ops.extras))
class SplitQuotedTest(unittest.TestCase):
"""A unittest class that tests the split_quoted function."""
@@ -1359,6 +1393,7 @@ class SplitQuotedTest(unittest.TestCase):
self.assertEqual(split_quoted('\\"\\""'), ['\\"'])
self.assertEqual(split_quoted('"\\"\\""'), ['""'])
if __name__ == "__main__":
doctest.testmod()
unittest.main()

View File

@@ -144,9 +144,10 @@ from zenmapCore.StringPool import unique
# The version of the Nmap DTD this file understands and emits.
XML_OUTPUT_VERSION = "1.04"
class HostInfo(object):
def __init__(self):
self.comment = None;
self.comment = None
self._tcpsequence = {}
self._osmatches = []
self._ports = []
@@ -233,13 +234,14 @@ class HostInfo(object):
"""Return the OS match with the highest accuracy."""
if not self._osmatches:
return None
def osmatch_key(osmatch):
try:
return -float(osmatch["accuracy"])
except ValueError:
return 0
return sorted(self._osmatches, key = osmatch_key)[0]
return sorted(self._osmatches, key=osmatch_key)[0]
# ports_used is a list like
# [{'state': u'open', 'portid': u'22', 'proto': u'tcp'},
@@ -262,7 +264,7 @@ class HostInfo(object):
return self._uptime
# Avoid empty dict return
return {"seconds":"", "lastboot":""}
return {"seconds": "", "lastboot": ""}
# ports is an array containing dicts of the form
# {'port_state': u'open', 'portid': u'22', 'protocol': u'tcp',
@@ -323,14 +325,16 @@ class HostInfo(object):
l.append((1, socket.inet_aton(self.ip["addr"])))
if self.ipv6:
try:
l.append((1, socket.inet_pton(socket.AF_INET6, self.ipv6["addr"])))
l.append((1,
socket.inet_pton(socket.AF_INET6, self.ipv6["addr"])))
except AttributeError:
# Windows doesn't have socket.inet_pton. Go alphabetical.
# Encode to a byte string for possible comparison with binary
# address strings (which can't be converted to unicode).
l.append((1, self.ipv6["addr"].encode("utf-8")))
if self.mac:
l.append((3, "".join([chr(int(x, 16)) for x in self.mac["addr"].split(":")])))
l.append((3, "".join(
chr(int(x, 16)) for x in self.mac["addr"].split(":"))))
l.sort()
return l
@@ -386,7 +390,8 @@ class HostInfo(object):
return self.get_port_count_by_states(('open', 'open|filtered'))
def get_filtered_ports(self):
return self.get_port_count_by_states(('filtered', 'open|filtered', 'closed|filtered'))
return self.get_port_count_by_states(
('filtered', 'open|filtered', 'closed|filtered'))
def get_closed_ports(self):
return self.get_port_count_by_states(('closed', 'closed|filtered'))
@@ -395,7 +400,7 @@ class HostInfo(object):
scanned = 0
for p in self.ports:
scanned+=1
scanned += 1
for extra in self.get_extraports():
scanned += int(extra["count"])
@@ -405,14 +410,16 @@ class HostInfo(object):
def get_services(self):
services = []
for p in self.ports:
services.append({"service_name":p.get("service_name", _("unknown")),
"portid":p.get("portid", ""),
"service_version":p.get("service_version",
_("Unknown version")),
"service_product":p.get("service_product", ""),
"service_extrainfo":p.get("service_extrainfo", ""),
"port_state":p.get("port_state", _("Unknown")),
"protocol":p.get("protocol", "")})
services.append({
"service_name": p.get("service_name", _("unknown")),
"portid": p.get("portid", ""),
"service_version": p.get("service_version",
_("Unknown version")),
"service_product": p.get("service_product", ""),
"service_extrainfo": p.get("service_extrainfo", ""),
"port_state": p.get("port_state", _("Unknown")),
"protocol": p.get("protocol", "")
})
return services
def get_trace(self):
@@ -448,19 +455,22 @@ class HostInfo(object):
services = property(get_services)
trace = property(get_trace, set_trace)
class ParserBasics(object):
def __init__ (self):
def __init__(self):
# This flag informs us whether the XML output file is temporary (True),
# or user specified (False). If any of them is user-specified, it
# doesn't get stripped out of the command string in set_nmap_command.
self.xml_is_temp = True
self.nmap = {'nmaprun':{},\
'scaninfo':[],\
'verbose':'',\
'debugging':'',\
'hosts':[],\
'runstats':{}}
self.nmap = {
'nmaprun': {},
'scaninfo': [],
'verbose': '',
'debugging': '',
'hosts': [],
'runstats': {}
}
self.ops = NmapOptions()
self._nmap_output = None
@@ -490,13 +500,13 @@ class ParserBasics(object):
def set_nmap_output(self, nmap_output):
self._nmap_output = nmap_output
def get_debugging_level (self):
def get_debugging_level(self):
return self.nmap.get('debugging', '')
def set_debugging_level(self, level):
self.nmap['debugging'] = level
def get_verbose_level (self):
def get_verbose_level(self):
return self.nmap.get('verbose', '')
def set_verbose_level(self, level):
@@ -508,7 +518,7 @@ class ParserBasics(object):
def set_scaninfo(self, info):
self.nmap['scaninfo'] = info
def get_services_scanned (self):
def get_services_scanned(self):
if self._services_scanned == None:
return self._services_scanned
@@ -519,10 +529,10 @@ class ParserBasics(object):
self._services_scanned = ','.join(services)
return self._services_scanned
def set_services_scanned (self, services_scanned):
def set_services_scanned(self, services_scanned):
self._services_scanned = services_scanned
def get_nmap_command (self):
def get_nmap_command(self):
return self.ops.render_string()
def set_nmap_command(self, command):
@@ -531,19 +541,19 @@ class ParserBasics(object):
self.ops["-oX"] = None
self.nmap['nmaprun']['args'] = self.ops.render_string()
def get_scan_type (self):
def get_scan_type(self):
types = []
for t in self.nmap.get('scaninfo', []):
types.append(t['type'])
return types
def get_protocol (self):
def get_protocol(self):
protocols = []
for proto in self.nmap.get('scaninfo', []):
protocols.append(proto['protocol'])
return protocols
def get_num_services (self):
def get_num_services(self):
if self._num_services == None:
return self._num_services
@@ -554,12 +564,12 @@ class ParserBasics(object):
self._num_services = num
return self._num_services
def set_num_services (self, num_services):
def set_num_services(self, num_services):
self._num_services = num_services
def get_date (self):
def get_date(self):
epoch = int(self.nmap['nmaprun'].get('start', '0'))
return time.localtime (epoch)
return time.localtime(epoch)
def get_start(self):
return self.nmap['nmaprun'].get('start', '0')
@@ -601,13 +611,13 @@ in epoch format!")
def get_formatted_date(self):
return time.strftime("%B %d, %Y - %H:%M", self.get_date())
def get_scanner (self):
def get_scanner(self):
return self.nmap['nmaprun'].get('scanner', '')
def set_scanner(self, scanner):
self.nmap['nmaprun']['scanner'] = scanner
def get_scanner_version (self):
def get_scanner_version(self):
return self.nmap['nmaprun'].get('version', '')
def set_scanner_version(self, version):
@@ -634,7 +644,7 @@ in epoch format!")
return []
return [host.ipv6 for host in hosts if host.ipv6 is not None]
def get_hostnames (self):
def get_hostnames(self):
hostnames = []
for host in self.nmap.get('hosts', []):
hostnames += host.get_hostnames()
@@ -667,7 +677,7 @@ in epoch format!")
def set_hosts_scanned(self, scanned):
self.nmap['runstats']['hosts_scanned'] = int(scanned)
def get_finish_time (self):
def get_finish_time(self):
return time.localtime(int(self.nmap['runstats'].get('finished_time',
'0')))
@@ -686,7 +696,8 @@ in epoch format!")
if scan_name:
return scan_name
if self.profile_name and self.get_targets():
return _("%s on %s") % (self.profile_name, join_quoted(self.get_targets()))
return _("%s on %s") % (self.profile_name,
join_quoted(self.get_targets()))
return self.get_nmap_command()
def set_scan_name(self, scan_name):
@@ -710,8 +721,8 @@ in epoch format!")
ports[int(item)] = []
ports[int(item)].append(scaninfo['protocol'])
else:
begin,end = item.split('-')
for port in range(int(begin),int(end)+1):
begin, end = item.split('-')
for port in range(int(begin), int(end) + 1):
if int(port) not in ports:
ports[int(port)] = []
ports[int(port)].append(scaninfo['protocol'])
@@ -752,6 +763,7 @@ in epoch format!")
_num_services = None
_services_scanned = None
class NmapParserSAX(ParserBasics, ContentHandler):
def __init__(self):
ParserBasics.__init__(self)
@@ -793,14 +805,15 @@ class NmapParserSAX(ParserBasics, ContentHandler):
def _parse_nmaprun(self, attrs):
run_tag = "nmaprun"
if self._nmap_output is None and attrs.has_key("nmap_output"):
if self._nmap_output is None and "nmap_output" in attrs:
self._nmap_output = attrs["nmap_output"]
self.nmap[run_tag]["profile_name"] = attrs.get("profile_name", "")
self.nmap[run_tag]["start"] = attrs.get("start", "")
self.nmap[run_tag]["args"] = attrs.get("args", "")
self.nmap[run_tag]["scanner"] = attrs.get("scanner", "")
self.nmap[run_tag]["version"] = attrs.get("version", "")
self.nmap[run_tag]["xmloutputversion"] = attrs.get("xmloutputversion", "")
self.nmap[run_tag]["xmloutputversion"] = attrs.get(
"xmloutputversion", "")
self.nmap_command = self.nmap[run_tag]["args"]
@@ -844,9 +857,9 @@ class NmapParserSAX(ParserBasics, ContentHandler):
self.host_info.set_state(unique(attrs.get("state", "")))
def _parse_host_address(self, attrs):
address_attributes = {"type":unique(attrs.get("addrtype", "")),
"vendor":attrs.get("vendor", ""),
"addr":attrs.get("addr", "")}
address_attributes = {"type": unique(attrs.get("addrtype", "")),
"vendor": attrs.get("vendor", ""),
"addr": attrs.get("addr", "")}
if address_attributes["type"] == "ipv4":
self.host_info.set_ip(address_attributes)
@@ -856,16 +869,16 @@ class NmapParserSAX(ParserBasics, ContentHandler):
self.host_info.set_mac(address_attributes)
def _parse_host_hostname(self, attrs):
self.list_hostnames.append({"hostname":attrs.get("name", ""),
"hostname_type":attrs.get("type", "")})
self.list_hostnames.append({"hostname": attrs.get("name", ""),
"hostname_type": attrs.get("type", "")})
def _parse_host_extraports(self, attrs):
self.list_extraports.append({"state":unique(attrs.get("state", "")),
"count":attrs.get("count", "")})
self.list_extraports.append({"state": unique(attrs.get("state", "")),
"count": attrs.get("count", "")})
def _parse_host_port(self, attrs):
self.dic_port = {"protocol":unique(attrs.get("protocol", "")),
"portid":unique(attrs.get("portid", ""))}
self.dic_port = {"protocol": unique(attrs.get("protocol", "")),
"portid": unique(attrs.get("portid", ""))}
def _parse_host_port_state(self, attrs):
self.dic_port["port_state"] = unique(attrs.get("state", ""))
@@ -886,10 +899,12 @@ class NmapParserSAX(ParserBasics, ContentHandler):
self.list_osmatch.append(osmatch)
def _parse_host_portused(self, attrs):
self.list_portused.append(self._parsing(attrs, ['state', 'proto', 'portid'], []))
self.list_portused.append(self._parsing(
attrs, ['state', 'proto', 'portid'], []))
def _parse_host_osclass(self, attrs):
self.list_osclass.append(self._parsing(attrs, ['type', 'vendor', 'osfamily', 'osgen'], ['accuracy']))
self.list_osclass.append(self._parsing(
attrs, ['type', 'vendor', 'osfamily', 'osgen'], ['accuracy']))
def _parsing(self, attrs, unique_names, other_names):
# Returns a dict with the attributes of a given tag with the
@@ -902,17 +917,20 @@ class NmapParserSAX(ParserBasics, ContentHandler):
return dic
def _parse_host_uptime(self, attrs):
self.host_info.set_uptime(self._parsing(attrs, [], ["seconds", "lastboot"]))
self.host_info.set_uptime(self._parsing(
attrs, [], ["seconds", "lastboot"]))
def _parse_host_tcpsequence(self, attrs):
self.host_info.set_tcpsequence(self._parsing(attrs, ['difficulty'], ['index', 'values']))
self.host_info.set_tcpsequence(self._parsing(
attrs, ['difficulty'], ['index', 'values']))
def _parse_host_tcptssequence(self, attrs):
self.host_info.set_tcptssequence(self._parsing(attrs, ['class'], ['values']))
self.host_info.set_tcptssequence(self._parsing(
attrs, ['class'], ['values']))
def _parse_host_ipidsequence(self, attrs):
self.host_info.set_ipidsequence(self._parsing(attrs, ['class'], ['values']))
self.host_info.set_ipidsequence(self._parsing(
attrs, ['class'], ['values']))
def _parse_host_trace(self, attrs):
trace = {}
@@ -1002,7 +1020,6 @@ class NmapParserSAX(ParserBasics, ContentHandler):
elif self.in_host and self.in_trace and name == "error":
self._parse_host_trace_error(attrs)
def endElement(self, name):
if name == "runstats":
self.in_interactive_output = False
@@ -1052,7 +1069,8 @@ class NmapParserSAX(ParserBasics, ContentHandler):
writer = XMLGenerator(f)
writer.startDocument()
if self.xml_stylesheet_data is not None:
writer.processingInstruction("xml-stylesheet", self.xml_stylesheet_data)
writer.processingInstruction(
"xml-stylesheet", self.xml_stylesheet_data)
self._write_nmaprun(writer)
self._write_scaninfo(writer)
self._write_verbose(writer)
@@ -1092,18 +1110,18 @@ class NmapParserSAX(ParserBasics, ContentHandler):
## Finished element
writer.startElement("finished",
Attributes(dict(time = str(self.finish_epoc_time),
timestr = time.ctime(time.mktime(self.get_finish_time())))))
Attributes(dict(time=str(self.finish_epoc_time),
timestr=time.ctime(time.mktime(
self.get_finish_time())))))
writer.endElement("finished")
## Hosts element
writer.startElement("hosts",
Attributes(dict(up = str(self.hosts_up),
down = str(self.hosts_down),
total = str(self.hosts_scanned))))
Attributes(dict(up=str(self.hosts_up),
down=str(self.hosts_down),
total=str(self.hosts_scanned))))
writer.endElement("hosts")
writer.endElement("runstats")
# End of Runstats element
#########################
@@ -1119,7 +1137,6 @@ class NmapParserSAX(ParserBasics, ContentHandler):
Attributes(dict(state=host.state)))
writer.endElement("status")
##################
# Address elements
## IPv4
@@ -1148,15 +1165,14 @@ class NmapParserSAX(ParserBasics, ContentHandler):
# End of Address elements
#########################
###################
# Hostnames element
writer.startElement("hostnames", Attributes({}))
for hname in host.hostnames:
writer.startElement("hostname",
Attributes(dict(name = hname.get("hostname", ""),
type = hname.get("hostname_type", ""))))
Attributes(dict(name=hname.get("hostname", ""),
type=hname.get("hostname_type", ""))))
writer.endElement("hostname")
@@ -1164,7 +1180,6 @@ class NmapParserSAX(ParserBasics, ContentHandler):
# End of Hostnames element
##########################
###############
# Ports element
writer.startElement("ports", Attributes({}))
@@ -1172,15 +1187,15 @@ class NmapParserSAX(ParserBasics, ContentHandler):
## Extraports elements
for ext in host.get_extraports():
writer.startElement("extraports",
Attributes(dict(count = ext.get("count", ""),
state = ext.get("state", ""))))
Attributes(dict(count=ext.get("count", ""),
state=ext.get("state", ""))))
writer.endElement("extraports")
## Port elements
for p in host.ports:
writer.startElement("port",
Attributes(dict(portid = p.get("portid", ""),
protocol = p.get("protocol", ""))))
Attributes(dict(portid=p.get("portid", ""),
protocol=p.get("protocol", ""))))
### Port state
writer.startElement("state",
@@ -1208,7 +1223,6 @@ class NmapParserSAX(ParserBasics, ContentHandler):
# End of Ports element
######################
############
# OS element
writer.startElement("os", Attributes({}))
@@ -1216,25 +1230,25 @@ class NmapParserSAX(ParserBasics, ContentHandler):
## Ports used elements
for pu in host.ports_used:
writer.startElement("portused",
Attributes(dict(state = pu.get("state", ""),
proto = pu.get("proto", ""),
portid = pu.get("portid", ""))))
Attributes(dict(state=pu.get("state", ""),
proto=pu.get("proto", ""),
portid=pu.get("portid", ""))))
writer.endElement("portused")
## Osmatch elements
for om in host.osmatches:
writer.startElement("osmatch",
Attributes(dict(name = om.get("name", ""),
accuracy = om.get("accuracy", ""),
line = om.get("line", ""))))
Attributes(dict(name=om.get("name", ""),
accuracy=om.get("accuracy", ""),
line=om.get("line", ""))))
## Osclass elements
for oc in om['osclasses']:
writer.startElement("osclass",
Attributes(dict(vendor = oc.get("vendor", ""),
osfamily = oc.get("osfamily", ""),
type = oc.get("type", ""),
osgen = oc.get("osgen", ""),
accuracy = oc.get("accuracy", ""))))
Attributes(dict(vendor=oc.get("vendor", ""),
osfamily=oc.get("osfamily", ""),
type=oc.get("type", ""),
osgen=oc.get("osgen", ""),
accuracy=oc.get("accuracy", ""))))
writer.endElement("osclass")
writer.endElement("osmatch")
@@ -1244,8 +1258,8 @@ class NmapParserSAX(ParserBasics, ContentHandler):
# Uptime element
writer.startElement("uptime",
Attributes(dict(seconds = host.uptime.get("seconds", ""),
lastboot = host.uptime.get("lastboot", ""))))
Attributes(dict(seconds=host.uptime.get("seconds", ""),
lastboot=host.uptime.get("lastboot", ""))))
writer.endElement("uptime")
#####################
@@ -1253,21 +1267,21 @@ class NmapParserSAX(ParserBasics, ContentHandler):
## TCP Sequence element
# Cannot use dict() here, because of the 'class' attribute.
writer.startElement("tcpsequence",
Attributes({"index":host.tcpsequence.get("index", ""),
"difficulty":host.tcpsequence.get("difficulty", ""),
"values":host.tcpsequence.get("values", "")}))
Attributes({"index": host.tcpsequence.get("index", ""),
"difficulty": host.tcpsequence.get("difficulty", ""),
"values": host.tcpsequence.get("values", "")}))
writer.endElement("tcpsequence")
## IP ID Sequence element
writer.startElement("ipidsequence",
Attributes({"class":host.ipidsequence.get("class", ""),
"values":host.ipidsequence.get("values", "")}))
Attributes({"class": host.ipidsequence.get("class", ""),
"values": host.ipidsequence.get("values", "")}))
writer.endElement("ipidsequence")
## TCP TS Sequence element
writer.startElement("tcptssequence",
Attributes({"class":host.tcptssequence.get("class", ""),
"values":host.tcptssequence.get("values", "")}))
Attributes({"class": host.tcptssequence.get("class", ""),
"values": host.tcptssequence.get("values", "")}))
writer.endElement("tcptssequence")
# End of sequences elements
###########################
@@ -1275,21 +1289,21 @@ class NmapParserSAX(ParserBasics, ContentHandler):
## Trace element
if len(host.trace) > 0:
writer.startElement("trace",
Attributes({"proto":host.trace.get("proto", ""),
"port":host.trace.get("port", "")}))
Attributes({"proto": host.trace.get("proto", ""),
"port": host.trace.get("port", "")}))
if "hops" in host.trace:
for hop in host.trace["hops"]:
writer.startElement("hop",
Attributes({"ttl":hop["ttl"],
"rtt":hop["rtt"],
"ipaddr":hop["ipaddr"],
"host":hop["host"]}))
Attributes({"ttl": hop["ttl"],
"rtt": hop["rtt"],
"ipaddr": hop["ipaddr"],
"host": hop["host"]}))
writer.endElement("hop")
if "error" in host.trace:
writer.startElement("error",
Attributes({"errorstr":host.trace["error"]}))
Attributes({"errorstr": host.trace["error"]}))
writer.endElement("error")
writer.endElement("trace")
@@ -1312,21 +1326,22 @@ class NmapParserSAX(ParserBasics, ContentHandler):
def _write_scaninfo(self, writer):
for scan in self.scaninfo:
writer.startElement("scaninfo",
Attributes(dict(type = scan.get("type", ""),
protocol = scan.get("protocol", ""),
numservices = scan.get("numservices", ""),
services = scan.get("services", ""))))
Attributes(dict(type=scan.get("type", ""),
protocol=scan.get("protocol", ""),
numservices=scan.get("numservices", ""),
services=scan.get("services", ""))))
writer.endElement("scaninfo")
def _write_nmaprun(self, writer):
writer.startElement("nmaprun",
Attributes(dict(args = str(self.nmap_command),
profile_name = str(self.profile_name),
scanner = str(self.scanner),
start = str(self.start),
startstr = time.ctime(time.mktime(self.get_date())),
version = str(self.scanner_version),
xmloutputversion = str(XML_OUTPUT_VERSION))))
Attributes(dict(args=str(self.nmap_command),
profile_name=str(self.profile_name),
scanner=str(self.scanner),
start=str(self.start),
startstr=time.ctime(
time.mktime(self.get_date())),
version=str(self.scanner_version),
xmloutputversion=str(XML_OUTPUT_VERSION))))
def set_unsaved(self):
self.unsaved = True
@@ -1334,6 +1349,7 @@ class NmapParserSAX(ParserBasics, ContentHandler):
def is_unsaved(self):
return self.unsaved
def nmap_parser_sax():
parser = make_parser()
nmap_parser = NmapParserSAX()
@@ -1345,6 +1361,7 @@ def nmap_parser_sax():
NmapParser = nmap_parser_sax
if __name__ == '__main__':
import sys

View File

@@ -133,6 +133,7 @@ from zenmapCore.Version import VERSION
from zenmapCore.Name import APP_NAME
from zenmapCore.UmitOptionParser import option_parser
# Find out the prefix under which data files (interface definition XML,
# pixmaps, etc.) are stored. This can vary depending on whether we are running
# in an executable package and what type of package it is, which we check using
@@ -161,6 +162,8 @@ MISC_DIR = join(prefix, "share", APP_NAME, "misc")
PIXMAPS_DIR = join(prefix, "share", "zenmap", "pixmaps")
DOCS_DIR = join(prefix, "share", APP_NAME, "docs")
NMAPDATADIR = join(prefix, "..")
def get_extra_executable_search_paths():
"""Return a list of additional executable search paths as a convenience for
platforms where the default PATH is inadequate."""
@@ -170,6 +173,7 @@ def get_extra_executable_search_paths():
return [dirname(sys.executable)]
return []
#######
# Paths
class Paths(object):
@@ -194,7 +198,8 @@ class Paths(object):
def __init__(self):
self.user_config_dir = option_parser.get_confdir()
self.user_config_file = os.path.join(self.user_config_dir, base_paths['user_config_file'])
self.user_config_file = os.path.join(
self.user_config_dir, base_paths['user_config_file'])
self.config_dir = CONFIG_DIR
self.locale_dir = LOCALE_DIR
self.pixmaps_dir = PIXMAPS_DIR
@@ -207,10 +212,12 @@ class Paths(object):
return self.__dict__[name]
elif name in self.config_files_list:
return return_if_exists(join(self.user_config_dir, base_paths[name]))
return return_if_exists(
join(self.user_config_dir, base_paths[name]))
elif name in self.empty_config_files_list:
return return_if_exists(join(self.user_config_dir, base_paths[name]), True)
return return_if_exists(
join(self.user_config_dir, base_paths[name]), True)
elif name in self.misc_files_list:
return return_if_exists(join(self.misc_dir, base_paths[name]))
@@ -223,15 +230,17 @@ class Paths(object):
def __setattr__(self, name, value):
self.__dict__[name] = value
def create_dir(path):
"""Create a directory with os.makedirs without raising an error if the
directory already exists."""
directory already exists."""
try:
os.makedirs(path)
except OSError, e:
if e.errno != errno.EEXIST:
raise
def create_user_config_dir(user_dir, template_dir):
"""Create a user configuration directory by creating the directory if
necessary, then copying all the files from the given template directory,
@@ -253,6 +262,7 @@ def create_user_config_dir(user_dir, template_dir):
shutil.copyfile(template_filename, user_filename)
log.debug(">>> Copy %s to %s." % (template_filename, user_filename))
def return_if_exists(path, create=False):
path = os.path.abspath(path)
if os.path.exists(path):

View File

@@ -124,6 +124,7 @@ from os import access, R_OK, W_OK
from os.path import dirname
from zenmapCore.Paths import Path
class RecentScans(object):
def __init__(self):
self.temp_list = []

View File

@@ -131,6 +131,7 @@ quoted_re = re.compile(r'\s*(([\'"])(.*?[^\\])\2)\s*([},=]|$)')
# "^%s*(['\"])%1%s*[},=]"
empty_re = re.compile(r'\s*(([\'"])\2)\s*([},=]|$)')
def parse_string(s, start):
"""Parses a single string that is quoted, unquoted or empty. It returns the
found string along with the next starting position """
@@ -140,6 +141,7 @@ def parse_string(s, start):
return m.group(1), m.end(1)
raise ValueError("No string found at %s." % repr(s[start:]))
def next_char(s, start):
"""Returns the next character and position in the string."""
while start < len(s) and s[start].isspace():
@@ -149,6 +151,7 @@ def next_char(s, start):
else:
return None, start
def parse_value(s, start):
"""If the string starting from start is a name-value pair, returns a
name-value tuple. Otherwise returns a plain string."""
@@ -172,6 +175,7 @@ def parse_value(s, start):
else:
return s[start:j], j
def parse_table(s, start):
"""This function is responsible for parsing a table; i.e, a string that
starts with '{'. It returns the position where the balancing pair of braces
@@ -192,6 +196,7 @@ def parse_table(s, start):
if nc == ",":
j += 1
def parse_script_args(s):
"""Main function responsible for parsing the script args and storing the
name-value pairs in a list. If an invalid argument is present it stores the
@@ -202,7 +207,8 @@ def parse_script_args(s):
while nc is not None:
val, j = parse_value(s, j)
if type(val) == str:
raise ValueError("Only name-value pairs expected in parse_script_args.")
raise ValueError(
"Only name-value pairs expected in parse_script_args.")
else:
args.append(val)
nc, j = next_char(s, j)
@@ -213,6 +219,7 @@ def parse_script_args(s):
return None
return args
def parse_script_args_dict(raw_argument):
"""Wrapper function that copies the name-value pairs from a list into a
dictionary."""
@@ -221,7 +228,7 @@ def parse_script_args_dict(raw_argument):
if args is None:
return None
for item in args:
if(len(item) == 2): # only key/value pairs are stored
if(len(item) == 2): # only key/value pairs are stored
args_dict[item[0]] = item[1]
return args_dict
@@ -234,7 +241,11 @@ if __name__ == '__main__':
('a={one,{two,{three}}}', [('a', '{one,{two,{three}}}')]),
('a={"quoted}quoted"}', [('a', '{"quoted}quoted"}')]),
('a="unterminated', None),
('user=foo,pass=",{}=bar",whois={whodb=nofollow+ripe},userdb=C:\\Some\\Path\\To\\File', [('user', 'foo'), ('pass', '",{}=bar"'), ('whois', '{whodb=nofollow+ripe}'), ('userdb', 'C:\\Some\\Path\\To\\File')]),
('user=foo,pass=",{}=bar",whois={whodb=nofollow+ripe},'
'userdb=C:\\Some\\Path\\To\\File',
[('user', 'foo'), ('pass', '",{}=bar"'),
('whois', '{whodb=nofollow+ripe}'),
('userdb', 'C:\\Some\\Path\\To\\File')]),
)
for test, expected in TESTS:
@@ -242,7 +253,7 @@ if __name__ == '__main__':
print args_dict
args = parse_script_args(test)
if args == expected:
print "PASS" , test
print "PASS", test
continue
print "FAIL", test
if args is None:

View File

@@ -131,6 +131,7 @@ import sys
from zenmapCore.Paths import Path
from zenmapCore.UmitLogging import log
class ScriptDB (object):
"""Class responsible for parsing the script.db file, fetching script
names and categories."""
@@ -138,7 +139,8 @@ class ScriptDB (object):
"a": "\a", "b": "\b", "f": "\f", "n": "\n", "r": "\r",
"t": "\t", "v": "\v", "\\": "\\", "\"": "\"", "'": "'", "0": "\0"
}
def __init__(self, script_db_path = None):
def __init__(self, script_db_path=None):
self.unget_buf = ""
self.f = open(script_db_path, "r")
@@ -162,7 +164,8 @@ class ScriptDB (object):
def parse(self):
"""Parses a script.db entry and returns it as a dictionary. An entry
looks like this:
Entry { filename = "afp-brute.nse", categories = { "auth", "intrusive", } }
Entry { filename = "afp-brute.nse", categories = \
{ "auth", "intrusive", } }
"""
entries = []
while True:
@@ -238,7 +241,8 @@ class ScriptDB (object):
if not token or token[0] != "string":
raise ScriptDBSyntaxError()
entry["filename"] = token[1]
self.expect((("delim", ","), ("ident", "categories"), ("delim", "="), ("delim", "{")))
self.expect((("delim", ","), ("ident", "categories"),
("delim", "="), ("delim", "{")))
entry["categories"] = []
token = self.token()
if token and token[0] == "string":
@@ -263,6 +267,7 @@ class ScriptDB (object):
def get_entries_list(self):
return self.entries_list
def nsedoc_tags_iter(f):
in_doc_comment = False
tag_name = None
@@ -296,6 +301,7 @@ def nsedoc_tags_iter(f):
tag_name = None
tag_text = None
class ScriptMetadata (object):
"""Class responsible for parsing all the script information."""
@@ -305,14 +311,15 @@ class ScriptMetadata (object):
def __init__(self, filename):
self.filename = filename
self.categories = []
self.arguments = [] # Arguments including library arguments.
self.arguments = [] # Arguments including library arguments.
self.license = ""
self.author = ""
self.description = ""
self.output = ""
self.usage = ""
url = property(lambda self: "http://nmap.org/nsedoc/scripts/" + os.path.splitext(self.filename)[0] + ".html")
url = property(lambda self: "http://nmap.org/nsedoc/scripts/"
"%s.html" % (os.path.splitext(self.filename)[0]))
def __init__(self, scripts_dir, nselib_dir):
self.scripts_dir = scripts_dir
@@ -351,13 +358,16 @@ class ScriptMetadata (object):
return contents
def get_string_variable(self, filename, varname):
contents = ScriptMetadata.get_file_contents(os.path.join(self.scripts_dir, filename))
contents = ScriptMetadata.get_file_contents(
os.path.join(self.scripts_dir, filename))
# Short string?
m = re.search(re.escape(varname) + r'\s*=\s*(["\'])(.*?[^\\])\1', contents)
m = re.search(
re.escape(varname) + r'\s*=\s*(["\'])(.*?[^\\])\1', contents)
if m:
return m.group(2)
# Long string?
m = re.search(re.escape(varname) + r'\s*=\s*\[(=*)\[(.*?)\]\1\]', contents, re.S)
m = re.search(
re.escape(varname) + r'\s*=\s*\[(=*)\[(.*?)\]\1\]', contents, re.S)
if m:
return m.group(2)
return None
@@ -398,7 +408,7 @@ class ScriptMetadata (object):
for tag_name, tag_text in nsedoc_tags_iter(f):
m = re.match(r'([\w._-]+)', tag_text)
if (tag_name == "arg" or tag_name == "args") and m:
args.append((m.group(1), re.sub(r'^[\w._-]+','',tag_text)))
args.append((m.group(1), re.sub(r'^[\w._-]+', '', tag_text)))
return args
def get_arguments(self, filename):
@@ -444,6 +454,7 @@ class ScriptMetadata (object):
self.library_arguments[libname] = self.get_script_args(filepath)
self.library_requires[libname] = self.get_requires(filepath)
def get_script_entries(scripts_dir, nselib_dir):
"""Merge the information obtained so far into one single entry for
each script and return it."""

View File

@@ -134,6 +134,7 @@ from zenmapCore.NmapOptions import NmapOptions
from zenmapCore.NmapParser import NmapParser
from zenmapCore.UmitLogging import log
class HostSearch(object):
@staticmethod
def match_target(host, name):
@@ -142,16 +143,20 @@ class HostSearch(object):
ip = host.get_ip()
ipv6 = host.get_ipv6()
if mac and mac.has_key('addr'):
if name in mac['addr'].lower(): return True
if ip and ip.has_key('addr'):
if name in ip['addr'].lower(): return True
if ipv6 and ipv6.has_key('addr'):
if name in ipv6['addr'].lower(): return True
if mac and 'addr' in mac:
if name in mac['addr'].lower():
return True
if ip and 'addr' in ip:
if name in ip['addr'].lower():
return True
if ipv6 and 'addr' in ipv6:
if name in ipv6['addr'].lower():
return True
if HostSearch.match_hostname(host, name):
return True
return False
@staticmethod
def match_hostname(host, hostname):
hostname = hostname.lower()
@@ -161,20 +166,27 @@ class HostSearch(object):
return True
else:
return False
@staticmethod
def match_service(host, service):
for port in host.get_ports():
# We concatenate all useful fields and add them to the list
if port['port_state'] not in ['open','open|filtered']:
if port['port_state'] not in ['open', 'open|filtered']:
continue
version = port.get("service_name", "") + " " + \
port.get("service_product", "") + " " + \
port.get("service_version", "") + " " + \
port.get("service_extrainfo", "")
version = " ".join(
port.get(x, "") for x in (
"service_name",
"service_product",
"service_version",
"service_extrainfo"
)
)
if service in version.lower():
return True
else:
return False
@staticmethod
def match_os(host, os):
os = os.lower()
@@ -191,6 +203,7 @@ class HostSearch(object):
return True
return False
@staticmethod
def match_port(host_ports, port, port_state):
# Check if the port is parsable, if not return False silently
@@ -203,6 +216,7 @@ class HostSearch(object):
return False
class SearchResult(object):
def __init__(self):
"""This constructor is always called by SearchResult subclasses."""
@@ -223,8 +237,8 @@ class SearchResult(object):
# No match => we discard this scan_result
break
else:
# All operator-matching functions have returned True, so this scan_result
# satisfies all conditions
# All operator-matching functions have returned True, so this
# scan_result satisfies all conditions
yield self.parsed_scan
def _match_all_args(self, operator, args):
@@ -250,7 +264,8 @@ class SearchResult(object):
if keyword == "*" or keyword == "":
return True
return keyword.lower() in str(self.parsed_scan.__getattribute__(property)).lower()
return keyword.lower() in str(
self.parsed_scan.__getattribute__(property)).lower()
def match_keyword(self, keyword):
log.debug("Match keyword: %s" % keyword)
@@ -261,7 +276,8 @@ class SearchResult(object):
def match_profile(self, profile):
log.debug("Match profile: %s" % profile)
log.debug("Comparing: %s == %s ??" % (str(self.parsed_scan.profile_name).lower(),
log.debug("Comparing: %s == %s ??" % (
str(self.parsed_scan.profile_name).lower(),
"*%s*" % profile.lower()))
if profile == "*" or profile == "" or \
profile.lower() in str(self.parsed_scan.profile_name).lower():
@@ -274,18 +290,20 @@ class SearchResult(object):
if option == "*" or option == "":
return True
# NOTE: Option matching treats "_" and "-" the same, just like the optcmp
# function in utils.cc . Also, option matching is case-sensitive.
# NOTE: Option matching treats "_" and "-" the same, just like the
# optcmp function in utils.cc . Also, option matching is
# case-sensitive.
option = option.replace("_", "-")
ops = NmapOptions()
ops.parse_string(self.parsed_scan.get_nmap_command())
if "(" in option and ")" in option:
# The syntax allows matching option arguments as "opt:option_name(value)".
# Since we've received only the "option_name(value)" part, we need to parse it.
# The syntax allows matching option arguments as
# "opt:option_name(value)". Since we've received only the
# "option_name(value)" part, we need to parse it.
optname = option[:option.find("(")]
optval = option[option.find("(")+1:option.find(")")]
optval = option[option.find("(") + 1:option.find(")")]
val = ops["--" + optname]
if val is None:
@@ -294,7 +312,8 @@ class SearchResult(object):
return False
return str(val) == optval or str(val) == optval
else:
return ops["--" + option] is not None or ops["-" + option] is not None
return (ops["--" + option] is not None or
ops["-" + option] is not None)
def match_date(self, date_arg, operator="date"):
# The parsed scan's get_date() returns a time.struct_time, so we
@@ -314,15 +333,17 @@ class SearchResult(object):
year, month, day = date_arg.split("-")
parsed_date = date(int(year), int(month), int(day))
elif re.match("[-|\+]\d+$", date_arg):
# We need to convert from the "-n" format (n days ago) to a date object
# (I found this in some old code, don't ask :) )
parsed_date = date.fromordinal(date.today().toordinal() + int(date_arg))
# We need to convert from the "-n" format (n days ago) to a date
# object (I found this in some old code, don't ask :) )
parsed_date = date.fromordinal(
date.today().toordinal() + int(date_arg))
else:
# Fail silently
return False
# Now that we have both the scan date and the user date converted to date objects,
# we need to make a comparison based on the operator (date, after, before).
# Now that we have both the scan date and the user date converted to
# date objects, we need to make a comparison based on the operator
# (date, after, before).
if operator == "date":
return abs((scan_date - parsed_date).days) <= fuzz
# We ignore fuzziness for after: and before:
@@ -351,10 +372,11 @@ class SearchResult(object):
return False
def match_os(self, os):
# If you have lots of big scans in your DB (with a lot of hosts scanned),
# you're probably better off using the keyword (freetext) search. Keyword
# search just greps through the nmap output, while this function iterates
# through all parsed OS-related values for every host in every scan!
# If you have lots of big scans in your DB (with a lot of hosts
# scanned), you're probably better off using the keyword (freetext)
# search. Keyword search just greps through the nmap output, while this
# function iterates through all parsed OS-related values for every host
# in every scan!
hosts = self.parsed_scan.get_hosts()
for host in hosts:
if HostSearch.match_os(host, os):
@@ -376,12 +398,13 @@ class SearchResult(object):
# Make a list of all scanned ports
services = []
for scaninfo in self.parsed_scan.get_scaninfo():
services.append( scaninfo["services"].split(",") )
services.append(scaninfo["services"].split(","))
# These two loops iterate over search ports and over scanned ports. As soon as
# the search finds a given port among the scanned ports, it breaks from the services
# loop and continues with the next port in the ports list. If a port isn't
# found in the services list, the function immediately returns False.
# These two loops iterate over search ports and over scanned ports. As
# soon as the search finds a given port among the scanned ports, it
# breaks from the services loop and continues with the next port in the
# ports list. If a port isn't found in the services list, the function
# immediately returns False.
for port in ports:
for service in services:
if "-" in service and \
@@ -394,7 +417,8 @@ class SearchResult(object):
else:
return False
else:
# The ports loop finished for all ports, which means the search was successful.
# The ports loop finished for all ports, which means the search was
# successful.
return True
def match_port(self, ports, port_state):
@@ -405,7 +429,8 @@ class SearchResult(object):
for host in self.parsed_scan.get_hosts():
for port in ports:
if not HostSearch.match_port(host.get_ports(), port, port_state):
if not HostSearch.match_port(
host.get_ports(), port, port_state):
break
else:
return True
@@ -445,15 +470,16 @@ class SearchResult(object):
return True
host = host.lower()
# Since the parser doesn't parse traceroute output, we need to cheat and look
# the host up in the Nmap output, in the Traceroute section of the scan.
# Since the parser doesn't parse traceroute output, we need to cheat
# and look the host up in the Nmap output, in the Traceroute section of
# the scan.
nmap_out = self.parsed_scan.get_nmap_output()
tr_pos = 0
traceroutes = [] # A scan holds one traceroute section per host
while tr_pos != -1:
# Find the beginning and the end of the traceroute section, and append
# the substring to the traceroutes list
tr_pos = nmap_out.find("TRACEROUTE", tr_pos+1)
# Find the beginning and the end of the traceroute section, and
# append the substring to the traceroutes list
tr_pos = nmap_out.find("TRACEROUTE", tr_pos + 1)
tr_end_pos = nmap_out.find("\n\n", tr_pos)
if tr_pos != -1:
traceroutes.append(nmap_out[tr_pos:tr_end_pos])
@@ -465,15 +491,18 @@ class SearchResult(object):
return False
def match_dir(self, dir):
# The dir: operator is handled by the SearchParser class, we ignore it here.
# The dir: operator is handled by the SearchParser class, we ignore it
# here.
return True
class SearchDummy(SearchResult):
"""A dummy search class that returns no results. It is used as a placeholder
when SearchDB can't be used."""
"""A dummy search class that returns no results. It is used as a
placeholder when SearchDB can't be used."""
def get_scan_results(self):
return []
class SearchDB(SearchResult, object):
def __init__(self):
SearchResult.__init__(self)
@@ -492,13 +521,15 @@ class SearchDB(SearchResult, object):
parsed.parse(buffer)
buffer.close()
except Exception, e:
log.warning(">>> Error loading scan with ID %u from database: %s" % (scan.scans_id, str(e)))
log.warning(">>> Error loading scan with ID %u from database: "
"%s" % (scan.scans_id, str(e)))
else:
self.scan_results.append(parsed)
def get_scan_results(self):
return self.scan_results
class SearchDir(SearchResult, object):
def __init__(self, search_directory, file_extensions=["usr"]):
SearchResult.__init__(self)
@@ -510,7 +541,8 @@ class SearchDir(SearchResult, object):
elif type(file_extensions) == type([]):
self.file_extensions = file_extensions
else:
raise Exception("Wrong file extension format! '%s'" % file_extensions)
raise Exception(
"Wrong file extension format! '%s'" % file_extensions)
log.debug(">>> Getting directory's scan results")
self.scan_results = []
@@ -534,6 +566,7 @@ class SearchDir(SearchResult, object):
def get_scan_results(self):
return self.scan_results
class SearchResultTest(unittest.TestCase):
class SearchClass(SearchResult):
"""This class is for use by the unit testing code"""
@@ -544,6 +577,7 @@ class SearchResultTest(unittest.TestCase):
scan = NmapParser()
scan.parse_file(filename)
self.scan_results.append(scan)
def get_scan_results(self):
return self.scan_results
@@ -553,31 +587,38 @@ class SearchResultTest(unittest.TestCase):
def _test_skeleton(self, key, val):
results = []
search = {key:[val]}
search = {key: [val]}
for scan in self.search_result.search(**search):
results.append(scan)
return len(results)
def test_match_os(self):
"""Test that checks if the match_os predicate works"""
assert(self._test_skeleton('os','linux') == 2)
assert(self._test_skeleton('os', 'linux') == 2)
def test_match_target(self):
"""Test that checks if the match_target predicate works"""
assert(self._test_skeleton('target','localhost') == 4)
assert(self._test_skeleton('target', 'localhost') == 4)
def test_match_port_open(self):
"""Test that checks if the match_open predicate works"""
assert(self._test_skeleton('open', '22') == 7)
def test_match_port_closed(self):
"""Test that checks if the match_closed predicate works"""
assert(self._test_skeleton('open', '22') == 7)
assert(self._test_skeleton('closed', '22') == 9)
def test_match_service(self):
"""Test that checks if the match_service predicate works"""
assert(self._test_skeleton('service', 'apache') == 9)
assert(self._test_skeleton('service', 'openssh') == 7)
def test_match_service_version(self):
"""Test that checks if the match_service predicate works when """
"""checking version"""
assert(self._test_skeleton('service', '2.0.52') == 7)
if __name__ == "__main__":
unittest.main()

View File

@@ -121,6 +121,8 @@
# ***************************************************************************/
UNIQUE_STRING_MAP = {}
def unique(s):
"""Return a single unique representation of s (unique as to id),
letting s be garbage collected."""

View File

@@ -124,6 +124,7 @@ from os import access, R_OK, W_OK
from os.path import dirname
from zenmapCore.Paths import Path
class TargetList(object):
def __init__(self):
self.temp_list = []

View File

@@ -130,10 +130,10 @@ from zenmapCore.UmitLogging import log
from zenmapCore.UmitConfigParser import UmitConfigParser
import zenmapCore.I18N
# This is the global configuration parser object that represents the contents of
# zenmap.conf. It should be initialized once by the application. Most
# interaction with the global parser is done by other classes in this file, like
# SearchConfig, that wrap specific configuration sections.
# This is the global configuration parser object that represents the contents
# of zenmap.conf. It should be initialized once by the application. Most
# interaction with the global parser is done by other classes in this file,
# like SearchConfig, that wrap specific configuration sections.
config_parser = UmitConfigParser()
# Check if running on Maemo
@@ -144,9 +144,11 @@ try:
except ImportError:
pass
def is_maemo():
return MAEMO
class SearchConfig(UmitConfigParser, object):
section_name = "search"
@@ -245,10 +247,11 @@ class SearchConfig(UmitConfigParser, object):
class Profile(UmitConfigParser, object):
"""This class represents not just one profile, but a whole collection of
them found in a config file such as scan_profiles.usp. The methods therefore
all take an argument that is the name of the profile to work on."""
them found in a config file such as scan_profiles.usp. The methods
therefore all take an argument that is the name of the profile to work
on."""
def __init__(self, user_profile = None, *args):
def __init__(self, user_profile=None, *args):
UmitConfigParser.__init__(self, *args)
if not user_profile:
@@ -272,10 +275,10 @@ class Profile(UmitConfigParser, object):
return self.set(profile, attribute, value)
def add_profile(self, profile_name, **attributes):
"""Add a profile with the given name and attributes to the collection of
profiles. If a profile with the same name exists, it is not overwritten,
and the method returns immediately. The backing file for the profiles is
automatically updated."""
"""Add a profile with the given name and attributes to the collection
of profiles. If a profile with the same name exists, it is not
overwritten, and the method returns immediately. The backing file for
the profiles is automatically updated."""
log.debug(">>> Add Profile '%s': %s" % (profile_name, attributes))
@@ -292,8 +295,10 @@ class Profile(UmitConfigParser, object):
self.save_changes()
def remove_profile(self, profile_name):
try: self.remove_section(profile_name)
except: pass
try:
self.remove_section(profile_name)
except:
pass
self.save_changes()
def _verify_profile(self, profile_name):
@@ -301,16 +306,17 @@ class Profile(UmitConfigParser, object):
return False
return True
class CommandProfile (Profile, object):
"""This class is a wrapper around Profile that provides accessors for the
attributes of a profile: command and description"""
def __init__(self, user_profile = None):
def __init__(self, user_profile=None):
Profile.__init__(self, user_profile)
def get_command(self, profile):
command_string = self._get_it(profile, 'command')
# Old versions of Zenmap used to append "%s" to commands and use that to
# substitute the target. Ignore it if present.
# Old versions of Zenmap used to append "%s" to commands and use that
# to substitute the target. Ignore it if present.
if command_string.endswith("%s"):
command_string = command_string[:-len("%s")]
return command_string
@@ -325,9 +331,9 @@ class CommandProfile (Profile, object):
self._set_it(profile, 'description', description)
def get_profile(self, profile_name):
return {'profile':profile_name, \
'command':self.get_command(profile_name), \
'description':self.get_description(profile_name)}
return {'profile': profile_name, \
'command': self.get_command(profile_name), \
'description': self.get_description(profile_name)}
class NmapOutputHighlight(object):
@@ -381,10 +387,14 @@ class NmapOutputHighlight(object):
tuple_regex = "[\(\[]\s?(\d+)\s?,\s?(\d+)\s?,\s?(\d+)\s?[\)\]]"
if isinstance(settings[3], basestring):
settings[3] = [int(t) for t in re.findall(tuple_regex, settings[3])[0]]
settings[3] = [
int(t) for t in re.findall(tuple_regex, settings[3])[0]
]
if isinstance(settings[4], basestring):
settings[4]= [int(h) for h in re.findall(tuple_regex, settings[4])[0]]
settings[4] = [
int(h) for h in re.findall(tuple_regex, settings[4])[0]
]
return settings
@@ -446,7 +456,8 @@ class NmapOutputHighlight(object):
try:
enable = config_parser.get("output_highlight", "enable_highlight")
except NoSectionError:
config_parser.set("output_highlight", "enable_highlight", str(True))
config_parser.set(
"output_highlight", "enable_highlight", str(True))
if enable == "False" or enable == "0" or enable == "":
return False
@@ -454,9 +465,11 @@ class NmapOutputHighlight(object):
def set_enable(self, enable):
if enable == False or enable == "0" or enable == None or enable == "":
config_parser.set("output_highlight", "enable_highlight", str(False))
config_parser.set(
"output_highlight", "enable_highlight", str(False))
else:
config_parser.set("output_highlight", "enable_highlight", str(True))
config_parser.set(
"output_highlight", "enable_highlight", str(True))
date = property(get_date, set_date)
hostname = property(get_hostname, set_hostname)
@@ -468,56 +481,68 @@ class NmapOutputHighlight(object):
details = property(get_details, set_details)
enable = property(get_enable, set_enable)
# These settings are made when there is nothing set yet. They set the "factory" \
# default to highlight colors
default_highlights = {"date":{"bold":str(True),
"italic":str(False),
"underline":str(False),
"text":[0, 0, 0],
"highlight":[65535, 65535, 65535],
"regex":"\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}\s.{1,4}"},
"hostname":{"bold":str(True),
"italic":str(True),
"underline":str(True),
"text":[0, 111, 65535],
"highlight":[65535, 65535, 65535],
"regex":"(\w{2,}://)*[\w-]{2,}\.[\w-]{2,}(\.[\w-]{2,})*(/[[\w-]{2,}]*)*"},
"ip":{"bold":str(True),
"italic":str(False),
"underline":str(False),
"text":[0, 0, 0],
"highlight":[65535, 65535, 65535],
"regex":"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"},
"port_list":{"bold":str(True),
"italic":str(False),
"underline":str(False),
"text":[0, 1272, 28362],
"highlight":[65535, 65535, 65535],
"regex":"PORT\s+STATE\s+SERVICE(\s+VERSION)?[^\n]*"},
"open_port":{"bold":str(True),
"italic":str(False),
"underline":str(False),
"text":[0, 41036, 2396],
"highlight":[65535, 65535, 65535],
"regex":"\d{1,5}/.{1,5}\s+open\s+.*"},
"closed_port":{"bold":str(False),
"italic":str(False),
"underline":str(False),
"text":[65535, 0, 0],
"highlight":[65535, 65535, 65535],
"regex":"\d{1,5}/.{1,5}\s+closed\s+.*"},
"filtered_port":{"bold":str(False),
"italic":str(False),
"underline":str(False),
"text":[38502, 39119, 0],
"highlight":[65535, 65535, 65535],
"regex":"\d{1,5}/.{1,5}\s+filtered\s+.*"},
"details":{"bold":str(True),
"italic":str(False),
"underline":str(True),
"text":[0, 0, 0],
"highlight":[65535, 65535, 65535],
"regex":"^(\w{2,}[\s]{,3}){,4}:"}}
# These settings are made when there is nothing set yet. They set the
# "factory" default to highlight colors
default_highlights = {
"date": {
"bold": str(True),
"italic": str(False),
"underline": str(False),
"text": [0, 0, 0],
"highlight": [65535, 65535, 65535],
"regex": "\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}\s.{1,4}"},
"hostname": {
"bold": str(True),
"italic": str(True),
"underline": str(True),
"text": [0, 111, 65535],
"highlight": [65535, 65535, 65535],
"regex": "(\w{2,}://)*[\w-]{2,}\.[\w-]{2,}"
"(\.[\w-]{2,})*(/[[\w-]{2,}]*)*"},
"ip": {
"bold": str(True),
"italic": str(False),
"underline": str(False),
"text": [0, 0, 0],
"highlight": [65535, 65535, 65535],
"regex": "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"},
"port_list": {
"bold": str(True),
"italic": str(False),
"underline": str(False),
"text": [0, 1272, 28362],
"highlight": [65535, 65535, 65535],
"regex": "PORT\s+STATE\s+SERVICE(\s+VERSION)?[^\n]*"},
"open_port": {
"bold": str(True),
"italic": str(False),
"underline": str(False),
"text": [0, 41036, 2396],
"highlight": [65535, 65535, 65535],
"regex": "\d{1,5}/.{1,5}\s+open\s+.*"},
"closed_port": {
"bold": str(False),
"italic": str(False),
"underline": str(False),
"text": [65535, 0, 0],
"highlight": [65535, 65535, 65535],
"regex": "\d{1,5}/.{1,5}\s+closed\s+.*"},
"filtered_port": {
"bold": str(False),
"italic": str(False),
"underline": str(False),
"text": [38502, 39119, 0],
"highlight": [65535, 65535, 65535],
"regex": "\d{1,5}/.{1,5}\s+filtered\s+.*"},
"details": {
"bold": str(True),
"italic": str(False),
"underline": str(True),
"text": [0, 0, 0],
"highlight": [65535, 65535, 65535],
"regex": "^(\w{2,}[\s]{,3}){,4}:"}
}
# Retrieve details from zenmap.conf regarding paths subsection
# (e.g. nmap_command_path) - jurand
@@ -530,8 +555,9 @@ class PathsConfig(object):
def __get_it(self, p_name, default):
try:
return config_parser.get(self.section_name, p_name)
except (NoOptionError,NoSectionError):
log.debug(">>> Using default \"%s\" for \"%s\"." % (default, p_name))
except (NoOptionError, NoSectionError):
log.debug(
">>> Using default \"%s\" for \"%s\"." % (default, p_name))
return default
def __set_it(self, property_name, settings):
@@ -550,17 +576,22 @@ class PathsConfig(object):
self.__set_it("ndiff_command_path", settings)
nmap_command_path = property(get_nmap_command_path, set_nmap_command_path)
ndiff_command_path = property(get_ndiff_command_path, set_ndiff_command_path)
ndiff_command_path = property(
get_ndiff_command_path, set_ndiff_command_path)
# Exceptions
class ProfileNotFound:
def __init__ (self, profile):
def __init__(self, profile):
self.profile = profile
def __str__ (self):
return "No profile named '"+self.profile+"' found!"
def __str__(self):
return "No profile named '" + self.profile + "' found!"
class ProfileCouldNotBeSaved:
def __init__ (self, profile):
def __init__(self, profile):
self.profile = profile
def __str__ (self):
return "Profile named '"+self.profile+"' could not be saved!"
def __str__(self):
return "Profile named '" + self.profile + "' could not be saved!"

View File

@@ -121,9 +121,11 @@
# ***************************************************************************/
from os.path import exists
from ConfigParser import ConfigParser, DEFAULTSECT, NoOptionError, NoSectionError
from ConfigParser import ConfigParser, DEFAULTSECT, NoOptionError, \
NoSectionError
from zenmapCore.UmitLogging import log
class UmitConfigParser(ConfigParser):
filenames = None
fp = None
@@ -158,9 +160,11 @@ class UmitConfigParser(ConfigParser):
if len(self.filenames) == 1:
filename = self.filenames[0]
else:
raise ValueError("UmitConfigParser can't handle a list of filenames: %s" % self.filenames)
raise ValueError("UmitConfigParser can't handle a list "
"of filenames: %s" % self.filenames)
else:
raise ValueError("UmitConfigParser can't handle a filename of type %s: %s" % (type(self.filenames), self.filenames))
raise ValueError("UmitConfigParser can't handle a filename of "
"type %s: %s" % (type(self.filenames), self.filenames))
self.write(open(filename, 'w'))
elif self.fp:
self.write(self.fp)
@@ -188,6 +192,7 @@ class UmitConfigParser(ConfigParser):
(key, str(value).replace('\n', '\n\t')))
fp.write("\n")
def test_umit_conf_content(filename):
parser = ConfigParser()
parser.read(filename)

View File

@@ -175,8 +175,8 @@ if isinstance(umitdb, str):
fs_enc = "UTF-8"
umitdb = umitdb.decode(fs_enc)
# pyslite 2.4.0 doesn't handle a unicode database name, though earlier and later
# versions do. Encode to UTF-8 as pysqlite would do internally anyway.
# pyslite 2.4.0 doesn't handle a unicode database name, though earlier and
# later versions do. Encode to UTF-8 as pysqlite would do internally anyway.
umitdb = umitdb.encode("UTF-8")
connection = sqlite.connect(umitdb)
@@ -192,6 +192,7 @@ except AttributeError:
# However, text_factory is available only in pysqlite 2.1.0 and later.
pass
class Table(object):
def __init__(self, table_name):
self.table_name = table_name
@@ -203,9 +204,11 @@ class Table(object):
if self.__getattribute__("_%s" % item_name):
return self.__getattribute__("_%s" % item_name)
sql = "SELECT %s FROM %s WHERE %s_id = %s" % (item_name, self.table_name,
self.table_name,
self.__getattribute__(self.table_id))
sql = "SELECT %s FROM %s WHERE %s_id = %s" % (
item_name,
self.table_name,
self.table_name,
self.__getattribute__(self.table_id))
self.cursor.execute(sql)
@@ -216,9 +219,11 @@ class Table(object):
if item_value == self.__getattribute__("_%s" % item_name):
return None
sql = "UPDATE %s SET %s = ? WHERE %s_id = %s" % (self.table_name, item_name,
self.table_name,
self.__getattribute__(self.table_id))
sql = "UPDATE %s SET %s = ? WHERE %s_id = %s" % (
self.table_name,
item_name,
self.table_name,
self.__getattribute__(self.table_id))
self.cursor.execute(sql, (item_value,))
connection.commit()
self.__setattr__("_%s" % item_name, item_value)
@@ -247,31 +252,30 @@ class Table(object):
self.cursor.execute(sql)
return self.cursor.fetchall()[0][0]
class UmitDB(object):
def __init__(self):
self.cursor = connection.cursor()
def create_db(self):
drop_string = ("DROP TABLE scans;",)
drop_string = "DROP TABLE scans;"
try:
for d in drop_string:
self.cursor.execute(d)
self.cursor.execute(drop_string)
except:
connection.rollback()
else:
connection.commit()
creation_string = """CREATE TABLE scans (
scans_id INTEGER PRIMARY KEY AUTOINCREMENT,
scan_name TEXT,
nmap_xml_output TEXT,
digest TEXT,
date INTEGER)"""
creation_string = ("""CREATE TABLE scans (scans_id INTEGER PRIMARY KEY AUTOINCREMENT,
scan_name TEXT,
nmap_xml_output TEXT,
digest TEXT,
date INTEGER)""",)
for c in creation_string:
self.cursor.execute(c)
connection.commit()
self.cursor.execute(creation_string)
connection.commit()
def add_scan(self, **kargs):
return Scans(**kargs)
@@ -289,11 +293,13 @@ class UmitDB(object):
def cleanup(self, save_time):
log.debug(">>> Cleaning up data base.")
log.debug(">>> Removing results olders than %s seconds" % save_time)
self.cursor.execute("SELECT scans_id FROM scans WHERE date < ?", (time() - save_time,))
self.cursor.execute("SELECT scans_id FROM scans WHERE date < ?",
(time() - save_time,))
for sid in [sid[0] for sid in self.cursor.fetchall()]:
log.debug(">>> Removing results with scans_id %s" % sid)
self.cursor.execute("DELETE FROM scans WHERE scans_id = ?", (sid, ))
self.cursor.execute("DELETE FROM scans WHERE scans_id = ?",
(sid, ))
else:
connection.commit()
log.debug(">>> Data base successfully cleaned up!")
@@ -310,25 +316,30 @@ class Scans(Table, object):
for k in kargs.keys():
if k not in fields:
raise Exception("Wrong table field passed to creation method. '%s'" % k)
raise Exception(
"Wrong table field passed to creation method. "
"'%s'" % k)
if "nmap_xml_output" not in kargs.keys() or not kargs["nmap_xml_output"]:
if ("nmap_xml_output" not in kargs.keys() or
not kargs["nmap_xml_output"]):
raise Exception("Can't save result without xml output")
if not self.verify_digest(md5(kargs["nmap_xml_output"]).hexdigest()):
if not self.verify_digest(
md5(kargs["nmap_xml_output"]).hexdigest()):
raise Exception("XML output registered already!")
self.scans_id = self.insert(**kargs)
def verify_digest(self, digest):
self.cursor.execute("SELECT scans_id FROM scans WHERE digest = ?", (digest, ))
self.cursor.execute(
"SELECT scans_id FROM scans WHERE digest = ?", (digest, ))
result = self.cursor.fetchall()
if result:
return False
return True
def add_host(self, **kargs):
kargs.update({self.table_id:self.scans_id})
kargs.update({self.table_id: self.scans_id})
return Hosts(**kargs)
def get_hosts(self):

View File

@@ -127,6 +127,7 @@ from zenmapCore.UmitOptionParser import option_parser
LOGLEVEL = option_parser.get_verbose()
class Log(Logger, object):
def __init__(self, name, level=0):
Logger.__init__(self, name, level)
@@ -143,7 +144,6 @@ class Log(Logger, object):
def set_formatter(self, fmt):
self.__formatter = Formatter(fmt)
format = "%(levelname)s - %(asctime)s - %(message)s"
formatter = property(get_formatter, set_formatter, doc="")

View File

@@ -128,6 +128,7 @@ from zenmapCore.Version import VERSION
import zenmapCore.I18N
from zenmapCore.BasePaths import base_paths
class UmitOptionParser(OptionParser):
def __init__(self, args=False):
OptionParser.__init__(self, version="%%prog %s" % VERSION)
@@ -135,10 +136,10 @@ class UmitOptionParser(OptionParser):
self.set_usage("%prog [options] [result files]")
self.add_option("--confdir",
default = base_paths["user_config_dir"],
dest = "confdir",
metavar = "DIR",
help = _("\
default=base_paths["user_config_dir"],
dest="confdir",
metavar="DIR",
help=_("\
Use DIR as the user configuration directory. Default: %default"))
## Open Scan Results (GUI)
@@ -163,7 +164,8 @@ scan result files."))
default=[],
action="callback",
callback=self.__nmap_callback,
help=_("Run %s with the specified args.") % NMAP_DISPLAY_NAME)
help=_("Run %s with the specified args."
) % NMAP_DISPLAY_NAME)
## Execute a profile against a target (GUI)
### Positional args should be taken as targets to feed this scan

View File

@@ -126,7 +126,8 @@ import webbrowser
from zenmapGUI.higwidgets.higdialogs import HIGDialog
from zenmapGUI.higwidgets.higwindows import HIGWindow
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox, hig_box_space_holder
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox, \
hig_box_space_holder
from zenmapGUI.higwidgets.higbuttons import HIGButton
from zenmapGUI.higwidgets.hignotebooks import HIGNotebook
from zenmapGUI.higwidgets.higscrollers import HIGScrolledWindow
@@ -141,6 +142,7 @@ import zenmapCore.I18N
# For escaping text in marked-up labels.
from xml.sax.saxutils import escape
class _program_entry(gtk.VBox):
"""A little box containing labels with a program's name and
description and a clickable link to its web site."""
@@ -149,7 +151,7 @@ class _program_entry(gtk.VBox):
# web site button.
NAME_WEB_SITE_SPACING = 20
def __init__(self, name = None, web_site = None, description = None):
def __init__(self, name=None, web_site=None, description=None):
gtk.VBox.__init__(self)
self.hbox = gtk.HBox(False, self.NAME_WEB_SITE_SPACING)
@@ -157,7 +159,9 @@ class _program_entry(gtk.VBox):
if name is not None:
name_label = gtk.Label()
name_label.set_markup("<span size=\"large\" weight=\"bold\">%s</span>" % escape(name))
name_label.set_markup(
'<span size="large" weight="bold">%s</span>' % escape(
name))
self.hbox.pack_start(name_label, False)
if web_site is not None:
@@ -180,41 +184,44 @@ class _program_entry(gtk.VBox):
def _link_button_open(self, widget):
webbrowser.open(widget.get_uri())
class About(HIGDialog):
"""An about dialog showing information about the program. It is meant to
have roughly the same feel as gtk.AboutDialog."""
def __init__(self):
HIGDialog.__init__(self)
self.set_title(_("About %s and %s") % (NMAP_DISPLAY_NAME, APP_DISPLAY_NAME))
self.set_title(_("About %s and %s") % (
NMAP_DISPLAY_NAME, APP_DISPLAY_NAME))
self.vbox.set_border_width(12)
self.vbox.set_spacing(12)
label = gtk.Label()
label.set_markup("<span size=\"xx-large\" weight=\"bold\">%s %s</span>" \
% (escape(APP_DISPLAY_NAME), escape(VERSION)))
label.set_markup(
'<span size="xx-large" weight="bold">%s %s</span>' % (
escape(APP_DISPLAY_NAME), escape(VERSION)))
label.set_selectable(True)
self.vbox.pack_start(label)
label = gtk.Label()
label.set_markup("<span size=\"small\">%s</span>" \
% (escape(APP_COPYRIGHT)))
label.set_markup(
'<span size="small">%s</span>' % (escape(APP_COPYRIGHT)))
self.vbox.pack_start(label)
entry = _program_entry(NMAP_DISPLAY_NAME, NMAP_WEB_SITE, _("""\
%s is a free and open source utility for network exploration and security \
auditing.""") % NMAP_DISPLAY_NAME)
entry = _program_entry(NMAP_DISPLAY_NAME, NMAP_WEB_SITE, _(
"%s is a free and open source utility for network exploration "
"and security auditing.") % NMAP_DISPLAY_NAME)
self.vbox.pack_start(entry)
entry = _program_entry(APP_DISPLAY_NAME, APP_WEB_SITE, _("""\
%s is a multi-platform graphical %s frontend and results viewer. It was \
originally derived from %s.""") \
% (APP_DISPLAY_NAME, NMAP_DISPLAY_NAME, UMIT_DISPLAY_NAME))
entry = _program_entry(APP_DISPLAY_NAME, APP_WEB_SITE, _(
"%s is a multi-platform graphical %s frontend and results viewer. "
"It was originally derived from %s.") % (
APP_DISPLAY_NAME, NMAP_DISPLAY_NAME, UMIT_DISPLAY_NAME))
self.vbox.pack_start(entry)
entry = _program_entry(UMIT_DISPLAY_NAME, UMIT_WEB_SITE, _("""\
%s is an %s GUI created as part of the Nmap/Google Summer of Code program.""") \
% (UMIT_DISPLAY_NAME, NMAP_DISPLAY_NAME))
entry = _program_entry(UMIT_DISPLAY_NAME, UMIT_WEB_SITE, _(
"%s is an %s GUI created as part of the Nmap/Google Summer "
"of Code program.") % (UMIT_DISPLAY_NAME, NMAP_DISPLAY_NAME))
button = gtk.Button(_("%s credits") % UMIT_DISPLAY_NAME)
button.connect("clicked", self._show_umit_credits)
entry.hbox.pack_start(button, False)
@@ -246,17 +253,20 @@ originally derived from %s.""") \
return
self._umit_credits_dialog = UmitCredits()
def credits_destroyed(widget):
# Mark that the credits dialog has been destroyed.
self._umit_credits_dialog = None
self._umit_credits_dialog.connect("destroy", credits_destroyed)
self._umit_credits_dialog.show_all()
class UmitCredits(HIGWindow):
def __init__(self):
HIGWindow.__init__(self)
self.set_title(_("%s credits") % UMIT_DISPLAY_NAME)
self.set_size_request(-1,250)
self.set_size_request(-1, 250)
self.set_position(gtk.WIN_POS_CENTER)
self.__create_widgets()
@@ -296,12 +306,18 @@ class UmitCredits(HIGWindow):
self.hbox._pack_expand_fill(hig_box_space_holder())
self.hbox._pack_noexpand_nofill(self.btn_close)
self.notebook.append_page(self.written_by_scroll, gtk.Label(_("Written by")))
self.notebook.append_page(self.design_scroll, gtk.Label(_("Design")))
self.notebook.append_page(self.soc2007_scroll, gtk.Label(_("SoC 2007")))
self.notebook.append_page(self.contributors_scroll, gtk.Label(_("Contributors")))
self.notebook.append_page(self.translation_scroll, gtk.Label(_("Translation")))
self.notebook.append_page(self.nokia_scroll, gtk.Label(_("Maemo")))
self.notebook.append_page(
self.written_by_scroll, gtk.Label(_("Written by")))
self.notebook.append_page(
self.design_scroll, gtk.Label(_("Design")))
self.notebook.append_page(
self.soc2007_scroll, gtk.Label(_("SoC 2007")))
self.notebook.append_page(
self.contributors_scroll, gtk.Label(_("Contributors")))
self.notebook.append_page(
self.translation_scroll, gtk.Label(_("Translation")))
self.notebook.append_page(
self.nokia_scroll, gtk.Label(_("Maemo")))
self.written_by_scroll.add(self.written_by_text)
self.written_by_text.set_wrap_mode(gtk.WRAP_NONE)
@@ -321,7 +337,7 @@ class UmitCredits(HIGWindow):
self.nokia_scroll.add(self.nokia_text)
self.nokia_text.set_wrap_mode(gtk.WRAP_NONE)
self.btn_close.connect('clicked', lambda x,y=None:self.destroy())
self.btn_close.connect('clicked', lambda x, y=None: self.destroy())
def set_text(self):
b = self.written_by_text.get_buffer()

View File

@@ -133,7 +133,7 @@ import ConfigParser
# Python 2.7 that otherwise causes an assertion failure. See
# https://bugzilla.redhat.com/show_bug.cgi?id=620216#c10.
import warnings
warnings.filterwarnings("error", module = "gtk", append = "True")
warnings.filterwarnings("error", module="gtk", append="True")
try:
import gtk
except Exception:
@@ -171,6 +171,7 @@ from zenmapGUI.higwidgets.higdialogs import HIGAlertDialog
# gtk.main_quit.
open_windows = []
def _destroy_callback(window):
open_windows.remove(window)
if len(open_windows) == 0:
@@ -183,6 +184,7 @@ def _destroy_callback(window):
# Cleaning up data base
UmitDB().cleanup(SearchConfig().converted_save_time)
def new_window():
w = ScanWindow()
w.connect("destroy", _destroy_callback)
@@ -193,11 +195,14 @@ def new_window():
open_windows.append(w)
return w
# Script found at http://www.py2exe.org/index.cgi/HowToDetermineIfRunningFromExe
# Script found at
# http://www.py2exe.org/index.cgi/HowToDetermineIfRunningFromExe
def main_is_frozen():
return (hasattr(sys, "frozen") # new py2exe
or hasattr(sys, "importers") # old py2exe
or imp.is_frozen("__main__")) # tools/freeze
return (hasattr(sys, "frozen") # new py2exe
or hasattr(sys, "importers") # old py2exe
or imp.is_frozen("__main__")) # tools/freeze
def is_root():
if 'NMAP_PRIVILEGED' in os.environ:
@@ -207,6 +212,7 @@ def is_root():
else:
return sys.platform == "win32" or os.getuid() == 0 or is_maemo()
def install_excepthook():
# This will catch exceptions and send them to bugzilla
def excepthook(type, value, tb):
@@ -218,7 +224,7 @@ def install_excepthook():
# produces a warning, but the lack of a display eventually causes a
# segmentation fault. See http://live.gnome.org/PyGTK/WhatsNew210.
import warnings
warnings.filterwarnings("error", module = "gtk")
warnings.filterwarnings("error", module="gtk")
import gtk
warnings.resetwarnings()
@@ -229,8 +235,7 @@ def install_excepthook():
if type == ImportError:
d = HIGAlertDialog(type=gtk.MESSAGE_ERROR,
message_format=_("Import error"),
secondary_text=_("""\
A required module was not found.
secondary_text=_("""A required module was not found.
""" + unicode(value)))
d.run()
@@ -246,6 +251,7 @@ A required module was not found.
sys.excepthook = excepthook
def safe_shutdown(signum, stack):
"""Kills any active scans/tabs and shuts down the application."""
log.debug("\n\n%s\nSAFE SHUTDOWN!\n%s\n" % ("#" * 30, "#" * 30))
@@ -256,6 +262,7 @@ def safe_shutdown(signum, stack):
sys.exit(signum)
def run():
if os.name == "posix":
signal.signal(signal.SIGHUP, safe_shutdown)
@@ -271,19 +278,25 @@ def run():
try:
# Create the ~/.zenmap directory by copying from the system-wide
# template directory.
zenmapCore.Paths.create_user_config_dir(Path.user_config_dir, Path.config_dir)
zenmapCore.Paths.create_user_config_dir(
Path.user_config_dir, Path.config_dir)
except (IOError, OSError), e:
error_dialog = HIGAlertDialog(message_format = _("Error creating the per-user configuration directory"),
secondary_text = _("""\
error_dialog = HIGAlertDialog(
message_format=_(
"Error creating the per-user configuration directory"),
secondary_text=_("""\
There was an error creating the directory %s or one of the files in it. \
The directory is created by copying the contents of %s. \
The specific error was\n\
\n\
%s\n\
\n\
The specific error was
%s
%s needs to create this directory to store information such as the list of \
scan profiles. Check for access to the directory and try again.\
""") % (repr(Path.user_config_dir), repr(Path.config_dir), repr(str(e)), APP_DISPLAY_NAME))
scan profiles. Check for access to the directory and try again.""") % (
repr(Path.user_config_dir), repr(Path.config_dir),
repr(str(e)), APP_DISPLAY_NAME
)
)
error_dialog.run()
error_dialog.destroy()
sys.exit(1)
@@ -292,16 +305,17 @@ scan profiles. Check for access to the directory and try again.\
# Read the ~/.zenmap/zenmap.conf configuration file.
zenmapCore.UmitConf.config_parser.read(Path.user_config_file)
except ConfigParser.ParsingError, e:
error_dialog = HIGAlertDialog(message_format = _("Error parsing the configuration file"),
secondary_text = _("""\
error_dialog = HIGAlertDialog(
message_format=_("Error parsing the configuration file"),
secondary_text=_("""\
There was an error parsing the configuration file %s. \
The specific error was\n\
\n\
%s\n\
\n\
The specific error was
%s
%s can continue without this file but any information in it will be ignored \
until it is repaired.\
""") % (Path.user_config_file, str(e), APP_DISPLAY_NAME))
until it is repaired.""") % (Path.user_config_file, str(e), APP_DISPLAY_NAME)
)
error_dialog.run()
error_dialog.destroy()
@@ -355,10 +369,13 @@ until it is repaired.\
if main_is_frozen():
gtk.gdk.threads_leave()
class NonRootWarning (HIGAlertDialog):
def __init__(self):
warning_text = _('''You are trying to run %s with a non-root user!\n
Some %s options need root privileges to work.''') % (APP_DISPLAY_NAME, NMAP_DISPLAY_NAME)
warning_text = _('''You are trying to run %s with a non-root user!
Some %s options need root privileges to work.''') % (
APP_DISPLAY_NAME, NMAP_DISPLAY_NAME)
HIGAlertDialog.__init__(self, message_format=_('Non-root user'),
secondary_text=warning_text)

View File

@@ -130,6 +130,7 @@ import zenmapCore.I18N
# For escaping text in marked-up labels.
from xml.sax.saxutils import escape
class BugReport(gtk.Window, object):
def __init__(self):
gtk.Window.__init__(self)
@@ -173,7 +174,11 @@ Code patches to fix bugs are even better than bug reports. Basic \
instructions for creating patch files with your changes are available at \
http://nmap.org/data/HACKING. Patches may be sent to nmap-dev \
(recommended) or to Fyodor directly.
""") % {"app": escape(APP_DISPLAY_NAME), "nmap": escape(NMAP_DISPLAY_NAME), "nmap_web": escape(NMAP_WEB_SITE)})
""") % {
"app": escape(APP_DISPLAY_NAME),
"nmap": escape(NMAP_DISPLAY_NAME),
"nmap_web": escape(NMAP_WEB_SITE)
})
self.vbox.add(self.text)
self.button_box.set_layout(gtk.BUTTONBOX_END)

View File

@@ -134,6 +134,7 @@ import zenmapCore.I18N
# For escaping text in marked-up labels.
from xml.sax.saxutils import escape
class CrashReport(HIGDialog):
def __init__(self, type, value, tb):
HIGDialog.__init__(self)
@@ -158,17 +159,16 @@ class CrashReport(HIGDialog):
self.description_text.set_editable(False)
self.bug_text = gtk.Label()
self.bug_text.set_markup(_("""\
An unexpected error has crashed %(app_name)s. Please copy the stack trace below and \
send it to the <a href="mailto:dev@nmap.org">dev@nmap.org</a> \
mailing list. (<a href="http://seclists.org/nmap-dev/">More about the list.</a>) \
The developers will see your report and try to fix the problem.""") % \
{ "app_name": escape(APP_DISPLAY_NAME) })
self.bug_text.set_markup(_('An unexpected error has crashed '
'%(app_name)s. Please copy the stack trace below and send it to '
'the <a href="mailto:dev@nmap.org">dev@nmap.org</a> mailing list. '
'(<a href="http://seclists.org/nmap-dev/">More about the list.</a>'
') The developers will see your report and try to fix the problem.'
) % {"app_name": escape(APP_DISPLAY_NAME)})
self.email_frame = gtk.Frame()
self.email_label = gtk.Label()
self.email_label.set_markup(_("""\
<b>Copy and email to <a href="mailto:dev@nmap.org">dev@nmap.org</a>:</b>\
"""))
self.email_label.set_markup(_('<b>Copy and email to '
'<a href="mailto:dev@nmap.org">dev@nmap.org</a>:</b>'))
self.btn_copy = gtk.Button(stock=gtk.STOCK_COPY)
self.btn_ok = gtk.Button(stock=gtk.STOCK_OK)
@@ -176,7 +176,8 @@ The developers will see your report and try to fix the problem.""") % \
def _pack_widgets(self):
self.description_scrolled.add(self.description_text)
self.description_scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.description_scrolled.set_policy(
gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.description_scrolled.set_size_request(400, 150)
self.description_text.set_wrap_mode(gtk.WRAP_WORD)
@@ -223,7 +224,7 @@ The developers will see your report and try to fix the problem.""") % \
sys.exit(0)
if __name__ == "__main__":
c = CrashReport(None,None,None)
c = CrashReport(None, None, None)
c.show_all()
c.connect("delete-event", lambda x, y: gtk.main_quit())

View File

@@ -129,7 +129,8 @@ import sys
import xml.sax
from zenmapGUI.higwidgets.higdialogs import HIGAlertDialog, HIGDialog
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox, hig_box_space_holder
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox, \
hig_box_space_holder
from zenmapGUI.higwidgets.higlabels import HIGSectionLabel
from zenmapGUI.higwidgets.higtables import HIGTable
from zenmapGUI.higwidgets.higbuttons import HIGButton
@@ -144,6 +145,7 @@ from zenmapGUI.FileChoosers import ResultsFileSingleChooserDialog
# In milliseconds.
NDIFF_CHECK_TIMEOUT = 200
class ScanChooser(HIGVBox):
"""This class allows the selection of scan results from the list of open
tabs or from a file. It emits the "changed" signal when the scan selection
@@ -193,7 +195,7 @@ class ScanChooser(HIGVBox):
def get_buffer(self):
return self.txt_scan_result.get_buffer()
def show_scan (self, widget):
def show_scan(self, widget):
nmap_output = self.get_nmap_output()
if nmap_output is not None:
self.txt_scan_result.get_buffer().set_text(nmap_output)
@@ -201,14 +203,15 @@ class ScanChooser(HIGVBox):
def normalize_output(self, output):
return "\n".join(output.split("\\n"))
def _pack_hbox (self):
def _pack_hbox(self):
self.hbox._pack_noexpand_nofill(hig_box_space_holder())
self.hbox._pack_expand_fill(self.table)
def _attaching_widgets (self):
self.table.attach(self.combo_scan, 0,1,0,1, yoptions=0)
self.table.attach(self.btn_open_scan, 1,2,0,1, yoptions=0, xoptions=0)
self.table.attach(self.exp_scan, 0,2,1,2)
def _attaching_widgets(self):
self.table.attach(self.combo_scan, 0, 1, 0, 1, yoptions=0)
self.table.attach(
self.btn_open_scan, 1, 2, 0, 1, yoptions=0, xoptions=0)
self.table.attach(self.exp_scan, 0, 2, 1, 2)
def _set_scrolled(self):
self.scrolled.set_border_width(5)
@@ -223,19 +226,20 @@ class ScanChooser(HIGVBox):
# Setting scrolled window
self.scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
def _set_text_view (self):
def _set_text_view(self):
self.txg_table = self.txt_scan_result.get_buffer().get_tag_table()
self.txg_table.add(self.txg_tag)
self.txg_tag.set_property("family", "Monospace")
self.txt_scan_result.set_wrap_mode(gtk.WRAP_WORD)
self.txt_scan_result.set_editable(False)
self.txt_scan_result.get_buffer().connect("changed", self._text_changed_cb)
self.txt_scan_result.get_buffer().connect(
"changed", self._text_changed_cb)
def _set_open_button (self):
def _set_open_button(self):
self.btn_open_scan.connect('clicked', self.open_file)
def open_file (self, widget):
def open_file(self, widget):
file_chooser = ResultsFileSingleChooserDialog(_("Select Scan Result"))
response = file_chooser.run()
@@ -248,15 +252,19 @@ class ScanChooser(HIGVBox):
except xml.sax.SAXParseException, e:
alert = HIGAlertDialog(
message_format='<b>%s</b>' % _('Error parsing file'),
secondary_text=_("The file is not an Nmap XML output file. \
The parsing error that occurred was\n%s") % str(e))
secondary_text=_(
"The file is not an Nmap XML output file. "
"The parsing error that occurred was\n%s") % str(e))
alert.run()
alert.destroy()
return False
except Exception, e:
alert = HIGAlertDialog(
message_format='<b>%s</b>' % _('Cannot open selected file'),
secondary_text=_("This error occurred while trying to open the file:\n%s") % str(e))
message_format='<b>%s</b>' % _(
'Cannot open selected file'),
secondary_text=_("""\
This error occurred while trying to open the file:
%s""") % str(e))
alert.run()
alert.destroy()
return False
@@ -276,9 +284,10 @@ The parsing error that occurred was\n%s") % str(e))
self.list_scan.append([new_scan_name])
self.scan_dict[new_scan_name] = parser
def _text_changed_cb (self, widget):
buff = self.txt_scan_result.get_buffer ()
buff.apply_tag(self.txg_tag, buff.get_start_iter(), buff.get_end_iter())
def _text_changed_cb(self, widget):
buff = self.txt_scan_result.get_buffer()
buff.apply_tag(
self.txg_tag, buff.get_start_iter(), buff.get_end_iter())
def get_parsed_scan(self):
"""Return the currently selected scan's parsed output as an NmapParser
@@ -306,9 +315,10 @@ class DiffWindow(gtk.Window):
gtk.Window.__init__(self)
self.set_title(_("Compare Results"))
self.ndiff_process = None
# We allow the user to start a new diff before the old one has finished.
# We have to keep references to old processes until they finish to avoid
# problems when tearing down the Python interpreter at program exit.
# We allow the user to start a new diff before the old one has
# finished. We have to keep references to old processes until they
# finish to avoid problems when tearing down the Python interpreter at
# program exit.
self.old_processes = []
self.timer_id = None
@@ -358,12 +368,13 @@ class DiffWindow(gtk.Window):
self.scan_chooser_a.connect('changed', self.refresh_diff)
self.scan_chooser_b.connect('changed', self.refresh_diff)
def refresh_diff (self, widget):
def refresh_diff(self, widget):
"""This method is called whenever the diff output might have changed,
such as when a different scan was selected in one of the choosers."""
log.debug("Refresh diff.")
if self.ndiff_process is not None and self.ndiff_process.poll() is None:
if (self.ndiff_process is not None and
self.ndiff_process.poll() is None):
# Put this in the list of old processes we keep track of.
self.old_processes.append(self.ndiff_process)
self.ndiff_process = None
@@ -378,14 +389,17 @@ class DiffWindow(gtk.Window):
self.ndiff_process = zenmapCore.Diff.ndiff(scan_a, scan_b)
except OSError, e:
alert = HIGAlertDialog(
message_format = _("Error running ndiff"),
secondary_text = _("There was an error running the ndiff program.\n\n") + str(e).decode(sys.getdefaultencoding(), "replace"))
message_format=_("Error running ndiff"),
secondary_text=_(
"There was an error running the ndiff program.\n\n"
) + str(e).decode(sys.getdefaultencoding(), "replace"))
alert.run()
alert.destroy()
else:
self.progress.show()
if self.timer_id is None:
self.timer_id = gobject.timeout_add(NDIFF_CHECK_TIMEOUT, self.check_ndiff_process)
self.timer_id = gobject.timeout_add(
NDIFF_CHECK_TIMEOUT, self.check_ndiff_process)
def check_ndiff_process(self):
"""Check if the ndiff subprocess is done and show the diff if it is.
@@ -412,21 +426,23 @@ class DiffWindow(gtk.Window):
diff = self.ndiff_process.get_scan_diff()
except zenmapCore.Diff.NdiffParseException, e:
alert = HIGAlertDialog(
message_format = _("Error parsing ndiff output"),
secondary_text = str(e))
message_format=_("Error parsing ndiff output"),
secondary_text=str(e))
alert.run()
alert.destroy()
else:
self.diff_view.show_diff(diff)
else:
# Unsuccessful completion.
error_text = _("The ndiff process terminated with status code %d.") % status
error_text = _(
"The ndiff process terminated with status code %d."
) % status
stderr = self.ndiff_process.stderr.read()
if len(stderr) > 0:
error_text += "\n\n" + stderr
alert = HIGAlertDialog(
message_format = _("Error running ndiff"),
secondary_text = error_text)
message_format=_("Error running ndiff"),
secondary_text=error_text)
alert.run()
alert.destroy()
@@ -445,6 +461,7 @@ class DiffWindow(gtk.Window):
def close(self, widget=None, extra=None):
self.destroy()
class DiffView(gtk.TextView):
REMOVE_COLOR = "#ffaaaa"
ADD_COLOR = "#ccffcc"
@@ -456,9 +473,10 @@ class DiffView(gtk.TextView):
buff = self.get_buffer()
# Create text markup tags.
buff.create_tag("=", font = "Monospace")
buff.create_tag("-", font = "Monospace", background = self.REMOVE_COLOR)
buff.create_tag("+", font = "Monospace", background = self.ADD_COLOR)
buff.create_tag("=", font="Monospace")
buff.create_tag(
"-", font="Monospace", background=self.REMOVE_COLOR)
buff.create_tag("+", font="Monospace", background=self.ADD_COLOR)
def clear(self):
self.get_buffer().set_text(u"")
@@ -494,6 +512,6 @@ if __name__ == "__main__":
"Parsed 4": parsed4})
dw.show_all()
dw.connect("delete-event", lambda x,y: gtk.main_quit())
dw.connect("delete-event", lambda x, y: gtk.main_quit())
gtk.main()

View File

@@ -128,6 +128,7 @@ import zenmapCore.I18N
RESPONSE_OPEN_DIRECTORY = 1
class AllFilesFileFilter(gtk.FileFilter):
def __init__(self):
gtk.FileFilter.__init__(self)
@@ -136,6 +137,7 @@ class AllFilesFileFilter(gtk.FileFilter):
self.add_pattern(pattern)
self.set_name(_("All files (%s)") % pattern)
class ResultsFileFilter(gtk.FileFilter):
def __init__(self):
gtk.FileFilter.__init__(self)
@@ -145,6 +147,7 @@ class ResultsFileFilter(gtk.FileFilter):
self.add_pattern(pattern)
self.set_name(_("Nmap XML files (%s)") % ", ".join(patterns))
class ScriptFileFilter(gtk.FileFilter):
def __init__(self):
gtk.FileFilter.__init__(self)
@@ -154,6 +157,7 @@ class ScriptFileFilter(gtk.FileFilter):
self.add_pattern(pattern)
self.set_name(_("NSE scripts (%s)") % ", ".join(patterns))
class UnicodeFileChooserDialog(gtk.FileChooserDialog):
"""This is a base class for file choosers. It is designed to ease the
retrieval of Unicode file names. On most platforms, the file names returned
@@ -173,6 +177,7 @@ class UnicodeFileChooserDialog(gtk.FileChooserDialog):
pass
return filename
class AllFilesFileChooserDialog(UnicodeFileChooserDialog):
def __init__(self, title="", parent=None,
action=gtk.FILE_CHOOSER_ACTION_OPEN,
@@ -184,6 +189,7 @@ class AllFilesFileChooserDialog(UnicodeFileChooserDialog):
self.set_default_response(gtk.RESPONSE_OK)
self.add_filter(AllFilesFileFilter())
class ResultsFileSingleChooserDialog(UnicodeFileChooserDialog):
"""This results file choose only allows the selection of single files, not
directories."""
@@ -198,6 +204,7 @@ class ResultsFileSingleChooserDialog(UnicodeFileChooserDialog):
for f in (ResultsFileFilter(), AllFilesFileFilter()):
self.add_filter(f)
class ResultsFileChooserDialog(UnicodeFileChooserDialog):
def __init__(self, title="", parent=None,
action=gtk.FILE_CHOOSER_ACTION_OPEN,
@@ -211,6 +218,7 @@ class ResultsFileChooserDialog(UnicodeFileChooserDialog):
for f in (ResultsFileFilter(), AllFilesFileFilter()):
self.add_filter(f)
class ScriptFileChooserDialog(UnicodeFileChooserDialog):
def __init__(self, title="", parent=None,
action=gtk.FILE_CHOOSER_ACTION_OPEN,
@@ -224,6 +232,7 @@ class ScriptFileChooserDialog(UnicodeFileChooserDialog):
for f in (ScriptFileFilter(), AllFilesFileFilter()):
self.add_filter(f)
class SaveResultsFileChooserDialog(UnicodeFileChooserDialog):
TYPES = (
(_("By extension"), None, None),
@@ -286,12 +295,14 @@ class SaveResultsFileChooserDialog(UnicodeFileChooserDialog):
def get_format(self):
"""Get the save format the user has chosen. It is a string, either
"text" or "xml"."""
filetype = self.combo.get_model().get_value(self.combo.get_active_iter(), 1)
filetype = self.combo.get_model().get_value(
self.combo.get_active_iter(), 1)
if filetype is None:
# Guess based on extension. "xml" is the default if unknown.
return self.EXTENSIONS.get(self.get_extension(), "xml")
return filetype
class DirectoryChooserDialog(UnicodeFileChooserDialog):
def __init__(self, title="", parent=None,
action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
@@ -301,6 +312,7 @@ class DirectoryChooserDialog(UnicodeFileChooserDialog):
UnicodeFileChooserDialog.__init__(self, title, parent, action, buttons)
self.set_default_response(gtk.RESPONSE_OK)
class SaveToDirectoryChooserDialog(UnicodeFileChooserDialog):
def __init__(self, title="", parent=None,
action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,

View File

@@ -4,6 +4,7 @@ import gobject
from zenmapGUI.higwidgets.higboxes import HIGHBox
from zenmapGUI.higwidgets.higlabels import HintWindow
class FilterBar(HIGHBox):
"""This is the bar that appears while the host filter is active. It allows
entering a string that restricts the set of visible hosts."""

View File

@@ -171,13 +171,18 @@ if pixmap_path:
# Try again.
pass
else:
log.warn('Could not find the icon for %s at any of (%s) in %s' % (icon_name, ', '.join(get_pixmap_file_names(icon_name, size)), pixmap_path))
log.warn('Could not find the icon for %s at '
'any of (%s) in %s' % (
icon_name,
', '.join(get_pixmap_file_names(icon_name, size)),
pixmap_path))
continue
iconset = gtk.IconSet(pixbuf)
iconfactory.add(key, iconset)
log.debug('Register %s icon name for file %s' % (key, file_path))
iconfactory.add_default()
def get_os_icon(host):
osmatch = host.get_best_osmatch()
if osmatch and osmatch['osclasses']:
@@ -190,6 +195,7 @@ def get_os_icon(host):
else:
return get_os(None, None, 'icon')
def get_os_logo(host):
osmatch = host.get_best_osmatch()
if osmatch and osmatch['osclasses']:
@@ -202,51 +208,53 @@ def get_os_logo(host):
else:
return get_os(None, None, 'logo')
def get_os(osfamily, osmatch, type):
if osfamily:
if osfamily == 'Linux':
if re.findall("ubuntu", osmatch.lower()):
# Ubuntu icon
return 'ubuntu_%s'%type
return 'ubuntu_%s' % type
elif re.findall("red hat", osmatch.lower()):
# RedHat icon
return 'redhat_%s'%type
return 'redhat_%s' % type
else:
# Generic Linux icon
return 'linux_%s'%type
return 'linux_%s' % type
elif osfamily == 'Windows':
# Windows icon
return 'win_%s'%type
return 'win_%s' % type
elif osfamily == 'OpenBSD':
# OpenBSD icon
return 'openbsd_%s'%type
return 'openbsd_%s' % type
elif osfamily == 'FreeBSD':
# FreeBSD icon
return 'freebsd_%s'%type
return 'freebsd_%s' % type
elif osfamily == 'NetBSD':
# NetBSD icon
return 'default_%s'%type
return 'default_%s' % type
elif osfamily == 'Solaris':
# Solaris icon
return 'solaris_%s'%type
return 'solaris_%s' % type
elif osfamily == 'OpenSolaris':
# OpenSolaris icon
return 'solaris_%s'%type
return 'solaris_%s' % type
elif osfamily == 'IRIX':
# Irix icon
return 'irix_%s'%type
return 'irix_%s' % type
elif osfamily == 'Mac OS X':
# Mac OS X icon
return 'macosx_%s'%type
return 'macosx_%s' % type
elif osfamily == 'Mac OS':
# Mac OS icon
return 'macosx_%s'%type
return 'macosx_%s' % type
else:
# Default OS icon
return 'default_%s'%type
return 'default_%s' % type
else:
# Unknown OS icon
return 'unknown_%s'%type
return 'unknown_%s' % type
def get_vulnerability_logo(open_ports):
open_ports = int(open_ports)

View File

@@ -159,6 +159,7 @@ hildon = None
if is_maemo():
import hildon
class UmitScanWindow(hildon.Window):
def __init__(self):
hildon.Window.__init__(self)
@@ -174,9 +175,10 @@ else:
HIGMainWindow.__init__(self)
self.vbox = gtk.VBox()
def can_print():
"""Return true if we have printing operations (PyGTK 2.10 or later) or false
otherwise."""
"""Return true if we have printing operations (PyGTK 2.10 or later) or
false otherwise."""
try:
gtk.PrintOperation
except AttributeError:
@@ -184,6 +186,7 @@ def can_print():
else:
return True
class ScanWindow(UmitScanWindow):
def __init__(self):
UmitScanWindow.__init__(self)
@@ -199,7 +202,7 @@ class ScanWindow(UmitScanWindow):
# self.vbox is a container for the menubar and the scan interface
self.add(self.vbox)
self.connect ('delete-event', self._exit_cb)
self.connect('delete-event', self._exit_cb)
self._create_ui_manager()
self._create_menubar()
self._create_scan_interface()
@@ -433,25 +436,29 @@ class ScanWindow(UmitScanWindow):
def _search_scan_result(self, widget):
"""Displays a search window."""
search_window = SearchWindow(self._load_search_result, self._append_search_result)
search_window = SearchWindow(
self._load_search_result, self._append_search_result)
search_window.show_all()
def _filter_cb(self, widget):
self.scan_interface.toggle_filter_bar()
def _load_search_result(self, results):
"""This function is passed as an argument to the SearchWindow.__init__ method.
When the user selects scans in the search window and clicks on \"Open\", this
function is called to load each of the selected scans into a new window."""
"""This function is passed as an argument to the SearchWindow.__init__
method. When the user selects scans in the search window and clicks on
"Open", this function is called to load each of the selected scans into
a new window."""
for result in results:
self._load(self.get_empty_interface(), parsed_result = results[result][1])
self._load(self.get_empty_interface(),
parsed_result=results[result][1])
def _append_search_result(self, results):
"""This function is passed as an argument to the SearchWindow.__init__ method.
When the user selects scans in the search window and clicks on \"Append\", this
function is called to append the selected scans into the current window."""
"""This function is passed as an argument to the SearchWindow.__init__
method. When the user selects scans in the search window and clicks on
"Append", this function is called to append the selected scans into the
current window."""
for result in results:
self._load(self.scan_interface, parsed_result = results[result][1])
self._load(self.scan_interface, parsed_result=results[result][1])
def store_result(self, scan_interface):
"""Stores the network inventory into the database."""
@@ -459,23 +466,28 @@ class ScanWindow(UmitScanWindow):
try:
scan_interface.inventory.save_to_db()
except Exception, e:
alert = HIGAlertDialog(message_format = _("Can't save to database"),
secondary_text = _("Can't store unsaved scans to the recent scans database:\n%s") % str(e))
alert = HIGAlertDialog(
message_format=_("Can't save to database"),
secondary_text=_("Can't store unsaved scans to the "
"recent scans database:\n%s") % str(e))
alert.run()
alert.destroy()
log.debug(">>> Can't save result to database: %s." % str(e))
def get_recent_scans(self):
"""Gets seven most recent scans and appends them to the default UI definition."""
"""Gets seven most recent scans and appends them to the default UI
definition."""
r_scans = recent_scans.get_recent_scans_list()
new_rscan_xml = ''
for scan in r_scans[:7]:
scan = scan.replace('\n','')
if os.access(split(scan)[0],os.R_OK) and isfile(scan):
scan = scan.replace('\n','')
new_rscan = (scan, None, scan, None, scan, self._load_recent_scan)
new_rscan_xml += "<menuitem action=%s/>\n" % xml.sax.saxutils.quoteattr(scan)
scan = scan.replace('\n', '')
if os.access(split(scan)[0], os.R_OK) and isfile(scan):
scan = scan.replace('\n', '')
new_rscan = (
scan, None, scan, None, scan, self._load_recent_scan)
new_rscan_xml += "<menuitem action=%s/>\n" % (
xml.sax.saxutils.quoteattr(scan))
self.main_actions.append(new_rscan)
else:
@@ -501,16 +513,19 @@ class ScanWindow(UmitScanWindow):
self.menubar.show_all()
def _create_scan_interface(self):
self.scan_interface.scan_result.scan_result_notebook.scans_list.append_button.connect("clicked", self._append_scan_results_cb)
self.scan_interface.scan_result.scan_result_notebook.nmap_output.connect("changed", self._displayed_scan_change_cb)
notebook = self.scan_interface.scan_result.scan_result_notebook
notebook.scans_list.append_button.connect(
"clicked", self._append_scan_results_cb)
notebook.nmap_output.connect("changed", self._displayed_scan_change_cb)
self._displayed_scan_change_cb(None)
self.scan_interface.show_all()
self.vbox.pack_start(self.scan_interface, True, True, 0)
def show_open_dialog(self, title = None):
def show_open_dialog(self, title=None):
"""Show a load file chooser and return the filename chosen."""
if self._results_filechooser_dialog is None:
self._results_filechooser_dialog = ResultsFileChooserDialog(title = title)
self._results_filechooser_dialog = ResultsFileChooserDialog(
title=title)
filename = None
response = self._results_filechooser_dialog.run()
@@ -519,8 +534,9 @@ class ScanWindow(UmitScanWindow):
elif response == RESPONSE_OPEN_DIRECTORY:
filename = self._results_filechooser_dialog.get_filename()
# Check if the selected filename is a directory. If not, we take only the
# directory part of the path, omitting the actual name of the selected file.
# Check if the selected filename is a directory. If not, we take
# only the directory part of the path, omitting the actual name of
# the selected file.
if filename is not None and not os.path.isdir(filename):
filename = os.path.dirname(filename)
@@ -528,8 +544,9 @@ class ScanWindow(UmitScanWindow):
return filename
def _load_scan_results_cb(self, p):
"""'Open Scan' callback function. Displays a file chooser dialog and loads the
scan from the selected file or from the selected directory."""
"""'Open Scan' callback function. Displays a file chooser dialog and
loads the scan from the selected file or from the selected
directory."""
filename = self.show_open_dialog(p.get_name())
if filename is not None:
scan_interface = self.get_empty_interface()
@@ -539,8 +556,8 @@ class ScanWindow(UmitScanWindow):
self._load(scan_interface, filename)
def _append_scan_results_cb(self, p):
"""'Append Scan' callback function. Displays a file chooser dialog and appends the
scan from the selected file into the current window."""
"""'Append Scan' callback function. Displays a file chooser dialog and
appends the scan from the selected file into the current window."""
filename = self.show_open_dialog(p.get_name())
if filename is not None:
if os.path.isdir(filename):
@@ -559,7 +576,8 @@ class ScanWindow(UmitScanWindow):
widget.set_sensitive(entry is not None)
def _load_recent_scan(self, widget):
"""A helper function for loading a recent scan directly from the menu."""
"""A helper function for loading a recent scan directly from the
menu."""
self._load(self.get_empty_interface(), widget.get_name())
def _load(self, scan_interface, filename=None, parsed_result=None):
@@ -587,54 +605,59 @@ class ScanWindow(UmitScanWindow):
def _load_directory(self, scan_interface, directory):
for file in os.listdir(directory):
if os.path.isdir(os.path.join(directory,file)):
if os.path.isdir(os.path.join(directory, file)):
continue
self._load(scan_interface, filename = os.path.join(directory, file))
self._load(scan_interface, filename=os.path.join(directory, file))
def _save_scan_results_cb(self, widget):
"""'Save Scan' callback function. If it's OK to save the scan, it displays a
'Save File' dialog and saves the scan. If not, it displays an appropriate
alert dialog."""
"""'Save Scan' callback function. If it's OK to save the scan, it
displays a 'Save File' dialog and saves the scan. If not, it displays
an appropriate alert dialog."""
num_scans = len(self.scan_interface.inventory.get_scans())
if num_scans == 0:
alert = HIGAlertDialog(message_format=_('Nothing to save'),
secondary_text=_("""\
There are no scans with results to be saved. Run a scan with the "Scan" button \
first."""))
alert = HIGAlertDialog(
message_format=_('Nothing to save'),
secondary_text=_(
'There are no scans with results to be saved. '
'Run a scan with the "Scan" button first.'))
alert.run()
alert.destroy()
return
num_scans_running = self.scan_interface.num_scans_running()
if num_scans_running > 0:
if num_scans_running == 1:
text = _("There is a scan still running. Wait until it finishes and then save.")
text = _("There is a scan still running. "
"Wait until it finishes and then save.")
else:
text = _("There are %u scans still running. Wait until they finish and then save.")\
% num_scans_running
text = _("There are %u scans still running. Wait until they "
"finish and then save.") % num_scans_running
alert = HIGAlertDialog(message_format=_('Scan is running'),
secondary_text=text)
alert.run()
alert.destroy()
return
# If there's more than one scan in the inventory, display a warning dialog saying
# that only the most recent scan will be saved
# If there's more than one scan in the inventory, display a warning
# dialog saying that only the most recent scan will be saved
selected = 0
if num_scans > 1:
#text = _("You have %u scans loaded in the current view. Only the most recent scan " \
# "will be saved." % num_scans)
#alert = HIGAlertDialog(message_format=_("More than one scan loaded"),
# secondary_text=text)
#text = _("You have %u scans loaded in the current view. "
# "Only the most recent scan will be saved." % num_scans)
#alert = HIGAlertDialog(
# message_format=_("More than one scan loaded"),
# secondary_text=text)
#alert.run()
#alert.destroy()
dlg = HIGDialog(title="Choose a scan to save",
parent=self,
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_SAVE, gtk.RESPONSE_OK))
dlg.vbox.pack_start(gtk.Label("You have %u scans loaded in the current view.\n" \
"Select the scan which you would like to save." \
% num_scans), False)
dlg = HIGDialog(
title="Choose a scan to save",
parent=self,
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_SAVE, gtk.RESPONSE_OK))
dlg.vbox.pack_start(gtk.Label(
"You have %u scans loaded in the current view.\n"
"Select the scan which you would like to save." % num_scans),
False)
scan_combo = gtk.combo_box_new_text()
for scan in self.scan_interface.inventory.get_scans():
scan_combo.append_text(scan.nmap_command)
@@ -653,7 +676,8 @@ first."""))
SaveResultsFileChooserDialog(title=_('Save Scan'))
# Supply a default file name if this scan was previously saved.
if self.scan_interface.saved_filename:
self._save_results_filechooser_dialog.set_filename(self.scan_interface.saved_filename)
self._save_results_filechooser_dialog.set_filename(
self.scan_interface.saved_filename)
response = self._save_results_filechooser_dialog.run()
@@ -680,19 +704,21 @@ This scan has not been run yet. Start the scan with the "Scan" button first.'))
num_scans_running = self.scan_interface.num_scans_running()
if num_scans_running > 0:
if num_scans_running == 1:
text = _("There is a scan still running. Wait until it finishes and then save.")
text = _("There is a scan still running. "
"Wait until it finishes and then save.")
else:
text = _("There are %u scans still running. Wait until they finish and then save.")\
% num_scans_running
text = _("There are %u scans still running. Wait until they "
"finish and then save.") % num_scans_running
alert = HIGAlertDialog(message_format=_('Scan is running'),
secondary_text=text)
alert.run()
alert.destroy()
return
# We have multiple scans in our network inventory, so we need to display a directory
# chooser dialog
dir_chooser = SaveToDirectoryChooserDialog(title=_("Choose a directory to save scans into"))
# We have multiple scans in our network inventory, so we need to
# display a directory chooser dialog
dir_chooser = SaveToDirectoryChooserDialog(
title=_("Choose a directory to save scans into"))
if dir_chooser.run() == gtk.RESPONSE_OK:
self._save_all(self.scan_interface, dir_chooser.get_filename())
dir_chooser.destroy()
@@ -729,16 +755,20 @@ This scan has not been run yet. Start the scan with the "Scan" button first.'))
recent_scans.add_recent_scan(filename)
recent_scans.save()
def _save(self, scan_interface, saved_filename, selected_index, format = "xml"):
def _save(self, scan_interface, saved_filename, selected_index,
format="xml"):
"""Saves the scan into a file with a given filename. Displays an alert
dialog if the save fails."""
log.debug(">>> File being saved: %s" % saved_filename)
try:
scan_interface.inventory.save_to_file(saved_filename, selected_index, format)
scan_interface.inventory.get_scans()[selected_index].unsaved = False
scan_interface.inventory.save_to_file(
saved_filename, selected_index, format)
scan_interface.inventory.get_scans()[selected_index].unsaved = \
False
except (OSError, IOError), e:
alert = HIGAlertDialog(message_format=_('Can\'t save file'),
secondary_text=_('Can\'t open file to write.\n%s') % str(e))
alert = HIGAlertDialog(
message_format=_("Can't save file"),
secondary_text=_("Can't open file to write.\n%s") % str(e))
alert.run()
alert.destroy()
else:
@@ -766,12 +796,16 @@ This scan has not been run yet. Start the scan with the "Scan" button first.'))
return w
def _new_scan_profile_cb(self, p):
pe = ProfileEditor(command=self.scan_interface.command_toolbar.command, deletable=False)
pe = ProfileEditor(
command=self.scan_interface.command_toolbar.command,
deletable=False)
pe.set_scan_interface(self.scan_interface)
pe.show_all()
def _edit_scan_profile_cb(self, p):
pe = ProfileEditor(profile_name=self.scan_interface.toolbar.selected_profile,deletable=True,overwrite=True)
pe = ProfileEditor(
profile_name=self.scan_interface.toolbar.selected_profile,
deletable=True, overwrite=True)
pe.set_scan_interface(self.scan_interface)
pe.show_all()
@@ -779,18 +813,20 @@ This scan has not been run yet. Start the scan with the "Scan" button first.'))
show_help()
def _exit_cb(self, *args):
"""Closes the window, prompting for confirmation if necessary. If one of
the tabs couldn't be closed, the function returns True and doesn't exit
the application."""
"""Closes the window, prompting for confirmation if necessary. If one
of the tabs couldn't be closed, the function returns True and doesn't
exit the application."""
if self.scan_interface.changed:
log.debug("Found changes on closing window")
dialog = HIGDialog(buttons=(_('Close anyway').encode('utf-8'), gtk.RESPONSE_CLOSE,
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
dialog = HIGDialog(
buttons=(_('Close anyway').encode('utf-8'),
gtk.RESPONSE_CLOSE, gtk.STOCK_CANCEL,
gtk.RESPONSE_CANCEL))
alert = HIGEntryLabel('<b>%s</b>' % _("Unsaved changes"))
text = HIGEntryLabel(_('The given scan has unsaved changes.\n\
What do you want to do?'))
text = HIGEntryLabel(_("The given scan has unsaved changes.\n"
"What do you want to do?"))
hbox = HIGHBox()
hbox.set_border_width(5)
hbox.set_spacing(12)
@@ -800,7 +836,8 @@ What do you want to do?'))
vbox.set_spacing(12)
image = gtk.Image()
image.set_from_stock(gtk.STOCK_DIALOG_QUESTION,gtk.ICON_SIZE_DIALOG)
image.set_from_stock(
gtk.STOCK_DIALOG_QUESTION, gtk.ICON_SIZE_DIALOG)
vbox.pack_start(alert)
vbox.pack_start(text)
@@ -822,13 +859,16 @@ What do you want to do?'))
elif self.scan_interface.num_scans_running() > 0:
log.debug("Trying to close a window with a running scan")
dialog = HIGDialog(buttons=(_('Close anyway').encode('utf-8'), gtk.RESPONSE_CLOSE,
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
dialog = HIGDialog(
buttons=(_('Close anyway').encode('utf-8'),
gtk.RESPONSE_CLOSE, gtk.STOCK_CANCEL,
gtk.RESPONSE_CANCEL))
alert = HIGEntryLabel('<b>%s</b>' % _("Trying to close"))
text = HIGEntryLabel(_('The window you are trying to close has a scan \
running at the background.\nWhat do you want to do?'))
text = HIGEntryLabel(_(
"The window you are trying to close has a scan running in "
"the background.\nWhat do you want to do?"))
hbox = HIGHBox()
hbox.set_border_width(5)
hbox.set_spacing(12)
@@ -838,7 +878,8 @@ running at the background.\nWhat do you want to do?'))
vbox.set_spacing(12)
image = gtk.Image()
image.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG)
image.set_from_stock(
gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG)
vbox.pack_start(alert)
vbox.pack_start(text)
@@ -865,7 +906,8 @@ running at the background.\nWhat do you want to do?'))
entry = self.scan_interface.scan_result.scan_result_notebook.nmap_output.get_active_entry()
if entry is None:
return False
zenmapGUI.Print.run_print_operation(self.scan_interface.inventory, entry)
zenmapGUI.Print.run_print_operation(
self.scan_interface.inventory, entry)
def _quit_cb(self, *args):
"""Close all open windows."""
@@ -874,12 +916,15 @@ running at the background.\nWhat do you want to do?'))
if window._exit_cb():
break
def _load_diff_compare_cb (self, widget=None, extra=None):
"""Loads all active scans into a dictionary, passes it to the DiffWindow
constructor, and then displays the 'Compare Results' window."""
self.diff_window = DiffWindow(self.scan_interface.inventory.get_scans())
def _load_diff_compare_cb(self, widget=None, extra=None):
"""Loads all active scans into a dictionary, passes it to the
DiffWindow constructor, and then displays the 'Compare Results'
window."""
self.diff_window = DiffWindow(
self.scan_interface.inventory.get_scans())
self.diff_window.show_all()
def show_help():
import urllib
import webbrowser

View File

@@ -134,6 +134,7 @@ from zenmapGUI.higwidgets.higtables import HIGTable
from zenmapGUI.higwidgets.higlabels import HIGEntryLabel
from zenmapGUI.higwidgets.higbuttons import HIGButton, HIGToggleButton
class NmapOutputProperties(HIGDialog):
def __init__(self, nmap_output_view):
HIGDialog.__init__(self, _("Nmap Output Properties"),
@@ -164,10 +165,14 @@ class NmapOutputProperties(HIGDialog):
#############
# Properties:
self.property_names = {"details": [_("details"), "MAC Address:"],
"port_list": [_("port listing title"), "PORT STATE SERVICE"],
"open_port": [_("open port"), "22/tcp open ssh"],
"closed_port": [_("closed port"), "70/tcp closed gopher"],
"filtered_port": [_("filtered port"), "80/tcp filtered http"],
"port_list": [_("port listing title"),
"PORT STATE SERVICE"],
"open_port": [_("open port"),
"22/tcp open ssh"],
"closed_port": [_("closed port"),
"70/tcp closed gopher"],
"filtered_port": [_("filtered port"),
"80/tcp filtered http"],
"date": [_("date"), "2006-05-26 11:14 BRT"],
"hostname": [_("hostname"), "scanme.nmap.org"],
"ip": [_("ip"), "127.0.0.1"]}
@@ -182,18 +187,23 @@ class NmapOutputProperties(HIGDialog):
self.property_names[p].append(gtk.gdk.Color(*settings[4]))
self.property_names[p].append(settings[5])
# Creating properties and related widgets and attaching it to main table
# Creating properties and related widgets and attaching it to main
# table
y1 = 0
y2 = 1
for p in self.property_names:
hp = HighlightProperty(p, self.property_names[p])
self.highlight_main_table.attach(hp.property_name_label, 0, 1, y1, y2)
self.highlight_main_table.attach(
hp.property_name_label, 0, 1, y1, y2)
self.highlight_main_table.attach(hp.example_label, 1, 2, y1, y2)
self.highlight_main_table.attach(hp.bold_tg_button, 2, 3, y1, y2)
self.highlight_main_table.attach(hp.italic_tg_button, 3, 4, y1, y2)
self.highlight_main_table.attach(hp.underline_tg_button, 4, 5, y1, y2)
self.highlight_main_table.attach(hp.text_color_button, 5, 6, y1, y2)
self.highlight_main_table.attach(hp.highlight_color_button, 6, 7, y1, y2)
self.highlight_main_table.attach(
hp.underline_tg_button, 4, 5, y1, y2)
self.highlight_main_table.attach(
hp.text_color_button, 5, 6, y1, y2)
self.highlight_main_table.attach(
hp.highlight_color_button, 6, 7, y1, y2)
# Setting example styles and colors
hp.update_example()
@@ -203,13 +213,13 @@ class NmapOutputProperties(HIGDialog):
y1 += 1
y2 += 1
# Packing main table into main vbox
self.highlight_main_vbox.pack_start(self.highlight_main_table)
# Adding color tab
self.properties_notebook.append_page(self.highlight_main_vbox,
gtk.Label(_("Highlight definitions")))
self.properties_notebook.append_page(
self.highlight_main_vbox,
gtk.Label(_("Highlight definitions")))
class HighlightProperty(object):
@@ -235,8 +245,10 @@ class HighlightProperty(object):
self.bold_tg_button = HIGToggleButton("", gtk.STOCK_BOLD)
self.italic_tg_button = HIGToggleButton("", gtk.STOCK_ITALIC)
self.underline_tg_button = HIGToggleButton("", gtk.STOCK_UNDERLINE)
self.text_color_button = HIGButton(_("Text"), stock=gtk.STOCK_SELECT_COLOR)
self.highlight_color_button = HIGButton(_("Highlight"), stock=gtk.STOCK_SELECT_COLOR)
self.text_color_button = HIGButton(
_("Text"), stock=gtk.STOCK_SELECT_COLOR)
self.highlight_color_button = HIGButton(
_("Highlight"), stock=gtk.STOCK_SELECT_COLOR)
def __connect_buttons(self):
self.bold_tg_button.connect("toggled", self.update_example)
@@ -244,20 +256,23 @@ class HighlightProperty(object):
self.underline_tg_button.connect("toggled", self.update_example)
self.text_color_button.connect("clicked", self.text_color_dialog)
self.highlight_color_button.connect("clicked", self.highlight_color_dialog)
self.highlight_color_button.connect(
"clicked", self.highlight_color_dialog)
####################################
# Text color dialog
def text_color_dialog(self, widget):
color_dialog = gtk.ColorSelectionDialog("%s %s" % (self.label, _("text color")))
color_dialog = gtk.ColorSelectionDialog(
"%s %s" % (self.label, _("text color")))
color_dialog.colorsel.set_current_color(self.text_color)
color_dialog.ok_button.connect("clicked", self.text_color_dialog_ok, color_dialog)
color_dialog.cancel_button.connect("clicked",
self.text_color_dialog_cancel, color_dialog)
color_dialog.connect("delete-event", self.text_color_dialog_close, color_dialog)
color_dialog.ok_button.connect(
"clicked", self.text_color_dialog_ok, color_dialog)
color_dialog.cancel_button.connect(
"clicked", self.text_color_dialog_cancel, color_dialog)
color_dialog.connect(
"delete-event", self.text_color_dialog_close, color_dialog)
color_dialog.run()
@@ -272,18 +287,21 @@ class HighlightProperty(object):
def text_color_dialog_close(self, widget, extra, color_dialog):
color_dialog.destroy()
#########################################
# Highlight color dialog
def highlight_color_dialog(self, widget):
color_dialog = gtk.ColorSelectionDialog("%s %s" % (self.property_name,
_("highlight color")))
color_dialog = gtk.ColorSelectionDialog(
"%s %s" % (self.property_name, _("highlight color")))
color_dialog.colorsel.set_current_color(self.highlight_color)
color_dialog.ok_button.connect("clicked", self.highlight_color_dialog_ok, color_dialog)
color_dialog.cancel_button.connect("clicked", self.highlight_color_dialog_cancel,
color_dialog.ok_button.connect(
"clicked", self.highlight_color_dialog_ok, color_dialog)
color_dialog.cancel_button.connect(
"clicked", self.highlight_color_dialog_cancel,
color_dialog)
color_dialog.connect("delete-event", self.highlight_color_dialog_close, color_dialog)
color_dialog.connect(
"delete-event", self.highlight_color_dialog_close,
color_dialog)
color_dialog.run()
@@ -304,8 +322,9 @@ class HighlightProperty(object):
attributes = pango.AttrList()
attributes.insert(pango.AttrForeground(self.text_color.red, self.text_color.green,
self.text_color.blue, start, end))
attributes.insert(
pango.AttrForeground(self.text_color.red,
self.text_color.green, self.text_color.blue, start, end))
attributes.insert(pango.AttrBackground(self.highlight_color.red,
self.highlight_color.green,
self.highlight_color.blue,
@@ -315,7 +334,8 @@ class HighlightProperty(object):
if self.bold_tg_button.get_active():
attributes.insert(pango.AttrWeight(pango.WEIGHT_HEAVY, start, end))
else:
attributes.insert(pango.AttrWeight(pango.WEIGHT_NORMAL, start, end))
attributes.insert(
pango.AttrWeight(pango.WEIGHT_NORMAL, start, end))
# Italic verification
if self.italic_tg_button.get_active():
@@ -325,13 +345,14 @@ class HighlightProperty(object):
# Underline verification
if self.underline_tg_button.get_active():
attributes.insert(pango.AttrUnderline(pango.UNDERLINE_SINGLE, start, end))
attributes.insert(
pango.AttrUnderline(pango.UNDERLINE_SINGLE, start, end))
else:
attributes.insert(pango.AttrUnderline(pango.UNDERLINE_NONE, start, end))
attributes.insert(
pango.AttrUnderline(pango.UNDERLINE_NONE, start, end))
self.example_label.set_attributes(attributes)
def show_bold(self, widget):
self.example_label.set_markup("<>")

View File

@@ -134,13 +134,14 @@ from zenmapCore.UmitConf import NmapOutputHighlight
from zenmapGUI.NmapOutputProperties import NmapOutputProperties
class NmapOutputViewer (gtk.VBox):
HIGHLIGHT_PROPERTIES = ["details", "date", "hostname", "ip", "port_list",
"open_port", "closed_port", "filtered_port"]
def __init__ (self, refresh=1, stop=1):
def __init__(self, refresh=1, stop=1):
self.nmap_highlight = NmapOutputHighlight()
gtk.VBox.__init__ (self)
gtk.VBox.__init__(self)
# Creating widgets
self.__create_widgets()
@@ -158,7 +159,7 @@ class NmapOutputViewer (gtk.VBox):
self.refreshing = True
# Adding widgets to the VBox
self.pack_start(self.scrolled, expand = True, fill = True)
self.pack_start(self.scrolled, expand=True, fill=True)
# The NmapCommand instance, if any, whose output is shown in this
# display.
@@ -166,16 +167,16 @@ class NmapOutputViewer (gtk.VBox):
# The position of the last read from the output stream.
self.output_file_pointer = None
def __create_widgets (self):
def __create_widgets(self):
# Creating widgets
self.scrolled = gtk.ScrolledWindow ()
self.text_view = gtk.TextView ()
self.scrolled = gtk.ScrolledWindow()
self.text_view = gtk.TextView()
def __set_scrolled_window (self):
def __set_scrolled_window(self):
# Seting scrolled window
self.scrolled.set_border_width (5)
self.scrolled.set_border_width(5)
self.scrolled.add(self.text_view)
self.scrolled.set_policy (gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
self.scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
def __set_text_view(self):
self.text_view.set_wrap_mode(gtk.WRAP_WORD)
@@ -205,8 +206,12 @@ class NmapOutputViewer (gtk.VBox):
text_color = settings[3]
highlight_color = settings[4]
tag.set_property("foreground", gtk.color_selection_palette_to_string([gtk.gdk.Color(*text_color),]))
tag.set_property("background", gtk.color_selection_palette_to_string([gtk.gdk.Color(*highlight_color),]))
tag.set_property(
"foreground", gtk.color_selection_palette_to_string(
[gtk.gdk.Color(*text_color), ]))
tag.set_property(
"background", gtk.color_selection_palette_to_string(
[gtk.gdk.Color(*highlight_color), ]))
def go_to_host(self, host):
"""Go to host line on nmap output result"""
@@ -218,7 +223,8 @@ class NmapOutputViewer (gtk.VBox):
for i in xrange(len(output)):
if re_host.match(output[i]):
self.text_view.scroll_to_iter(buff.get_iter_at_line(i), 0, True, 0, 0)
self.text_view.scroll_to_iter(
buff.get_iter_at_line(i), 0, True, 0, 0)
break
def show_output_properties(self, widget):
@@ -259,7 +265,7 @@ class NmapOutputViewer (gtk.VBox):
self.nmap_highlight.save_changes()
self.apply_highlighting()
def apply_highlighting(self, start_iter = None, end_iter = None):
def apply_highlighting(self, start_iter=None, end_iter=None):
buf = self.text_view.get_buffer()
if start_iter is None:
@@ -302,7 +308,7 @@ class NmapOutputViewer (gtk.VBox):
self.output_file_pointer = None
self.refresh_output()
def refresh_output(self, widget = None):
def refresh_output(self, widget=None):
"""Update the output from the latest output of the command associated
with this view, as set by set_command_execution. It has no effect if no
command has been set."""
@@ -316,7 +322,8 @@ class NmapOutputViewer (gtk.VBox):
pos = self.command_execution.stdout_file.tell()
new_output = self.command_execution.stdout_file.read()
self.output_file_pointer = self.command_execution.stdout_file.tell()
# print "read %d -> %d %d" % (pos, self.output_file_pointer, len(new_output))
# print "read %d -> %d %d" % (
# pos, self.output_file_pointer, len(new_output))
v_adj = self.scrolled.get_vadjustment()
if new_output and v_adj is not None:
@@ -324,15 +331,19 @@ class NmapOutputViewer (gtk.VBox):
at_end = (v_adj.value >= v_adj.upper - v_adj.page_size)
buf = self.text_view.get_buffer()
prev_end_mark = buf.create_mark(None, buf.get_end_iter(), left_gravity = True)
prev_end_mark = buf.create_mark(
None, buf.get_end_iter(), left_gravity=True)
buf.insert(buf.get_end_iter(), new_output)
# Highlight the new text.
self.apply_highlighting(buf.get_iter_at_mark(prev_end_mark), buf.get_end_iter())
self.apply_highlighting(
buf.get_iter_at_mark(prev_end_mark), buf.get_end_iter())
if at_end:
# If we were already scrolled to the bottom, scroll back to the
# bottom again. Also do it in an idle handler in case the added
# text causes a scroll bar to appear and reflow the text, making
# the text a bit taller.
# text causes a scroll bar to appear and reflow the text,
# making the text a bit taller.
self.text_view.scroll_mark_onscreen(self.end_mark)
gobject.idle_add(lambda: self.text_view.scroll_mark_onscreen(self.end_mark))
gobject.idle_add(
lambda: self.text_view.scroll_mark_onscreen(
self.end_mark))

View File

@@ -138,6 +138,7 @@ import zenmapCore.I18N
from zenmapCore.UmitLogging import log
from zenmapGUI.ScriptInterface import *
def get_option_check_auxiliary_widget(option, ops, check):
if option in ("-sI", "-b", "--script", "--script-args", "--exclude", "-p",
"-D", "-S", "--source-port", "-e", "--ttl", "-iR", "--max-retries",
@@ -159,6 +160,7 @@ def get_option_check_auxiliary_widget(option, ops, check):
else:
assert False, "Unknown option %s" % option
class OptionEntry(gtk.Entry):
def __init__(self, option, ops, check):
gtk.Entry.__init__(self)
@@ -187,6 +189,7 @@ class OptionEntry(gtk.Entry):
self.check.set_active(True)
self.ops[self.option] = self.get_text().decode("UTF-8")
class OptionExtras(gtk.Entry):
def __init__(self, option, ops, check):
gtk.Entry.__init__(self)
@@ -214,6 +217,7 @@ class OptionExtras(gtk.Entry):
self.check.set_active(True)
self.ops.extras = [self.get_text().decode("UTF-8")]
class OptionLevel(gtk.SpinButton):
def __init__(self, option, ops, check):
gtk.SpinButton.__init__(self, gtk.Adjustment(0, 0, 10, 1), 0.0, 0)
@@ -243,6 +247,7 @@ class OptionLevel(gtk.SpinButton):
self.check.set_active(True)
self.ops[self.option] = int(self.get_adjustment().get_value())
class OptionFile(gtk.HBox):
__gsignals__ = {
"changed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ())
@@ -257,7 +262,7 @@ class OptionFile(gtk.HBox):
self.entry = gtk.Entry()
self.pack_start(self.entry, True, True)
button = HIGButton(stock = gtk.STOCK_OPEN)
button = HIGButton(stock=gtk.STOCK_OPEN)
self.pack_start(button, False)
button.connect("clicked", self.clicked_cb)
@@ -291,6 +296,7 @@ class OptionFile(gtk.HBox):
self.entry.set_text(dialog.get_filename())
dialog.destroy()
class TargetEntry(gtk.Entry):
def __init__(self, ops):
gtk.Entry.__init__(self)
@@ -307,11 +313,12 @@ class TargetEntry(gtk.Entry):
def get_targets(self):
return split_quoted(self.get_text().decode("UTF-8"))
class OptionTab(object):
def __init__(self, root_tab, ops, update_command, help_buf):
actions = {'target':self.__parse_target,
'option_list':self.__parse_option_list,
'option_check':self.__parse_option_check}
actions = {'target': self.__parse_target,
'option_list': self.__parse_option_list,
'option_check': self.__parse_option_check}
self.ops = ops
self.update_command = update_command
@@ -321,8 +328,10 @@ class OptionTab(object):
self.notscripttab = False # assume every tab is scripting tab
self.widgets_list = []
for option_element in root_tab.childNodes:
try:option_element.tagName
except:pass
try:
option_element.tagName
except:
pass
else:
if option_element.tagName in actions.keys():
parse_func = actions[option_element.tagName]
@@ -339,7 +348,8 @@ class OptionTab(object):
def __parse_option_list(self, option_list_element):
children = option_list_element.getElementsByTagName(u'option')
label_widget = HIGEntryLabel(_(option_list_element.getAttribute(u'label')))
label_widget = HIGEntryLabel(
_(option_list_element.getAttribute(u'label')))
option_list_widget = OptionList(self.ops)
for child in children:
@@ -348,8 +358,10 @@ class OptionTab(object):
label = _(child.getAttribute(u'label'))
option_list_widget.append(option, argument, label)
self.profilehelp.add_label(option, label)
self.profilehelp.add_shortdesc(option, _(child.getAttribute(u'short_desc')))
self.profilehelp.add_example(option, child.getAttribute(u'example'))
self.profilehelp.add_shortdesc(
option, _(child.getAttribute(u'short_desc')))
self.profilehelp.add_example(
option, child.getAttribute(u'example'))
option_list_widget.update()
@@ -369,10 +381,12 @@ class OptionTab(object):
self.profilehelp.add_example(option, example)
check = OptionCheck(option, label)
auxiliary_widget = get_option_check_auxiliary_widget(option, self.ops, check)
auxiliary_widget = get_option_check_auxiliary_widget(
option, self.ops, check)
if auxiliary_widget is not None:
auxiliary_widget.connect("changed", self.update_auxiliary_widget)
auxiliary_widget.connect('enter-notify-event', self.enter_notify_event_cb, option)
auxiliary_widget.connect(
'enter-notify-event', self.enter_notify_event_cb, option)
else:
check.set_active(not not self.ops[option])
@@ -381,14 +395,14 @@ class OptionTab(object):
return check, auxiliary_widget
def fill_table(self, table, expand_fill = True):
def fill_table(self, table, expand_fill=True):
yopt = (0, gtk.EXPAND | gtk.FILL)[expand_fill]
for y, widget in enumerate(self.widgets_list):
if widget[1] == None:
table.attach(widget[0], 0, 2, y, y+1, yoptions=yopt)
table.attach(widget[0], 0, 2, y, y + 1, yoptions=yopt)
else:
table.attach(widget[0], 0, 1, y, y+1, yoptions=yopt)
table.attach(widget[1], 1, 2, y, y+1, yoptions=yopt)
table.attach(widget[0], 0, 1, y, y + 1, yoptions=yopt)
table.attach(widget[1], 1, 2, y, y + 1, yoptions=yopt)
def update_auxiliary_widget(self, auxiliary_widget):
self.update_command()
@@ -446,6 +460,7 @@ class OptionTab(object):
def enter_notify_event_cb(self, event, widget, option):
self.show_help_for_option(option)
class OptionBuilder(object):
def __init__(self, xml_file, ops, update_func, help_buf):
"""
@@ -463,7 +478,6 @@ class OptionBuilder(object):
self.root_tag = "interface"
self.xml = self.xml.getElementsByTagName(self.root_tag)[0]
self.groups = self.__parse_groups()
@@ -490,11 +504,13 @@ class OptionBuilder(object):
dic = {}
for tab_name in self.groups:
if tab_name != "Scripting":
dic[tab_name] = OptionTab(self.xml.getElementsByTagName(tab_name)[0],
self.ops, self.update_func, self.help_buf)
dic[tab_name] = OptionTab(
self.xml.getElementsByTagName(tab_name)[0], self.ops,
self.update_func, self.help_buf)
dic[tab_name].notscripttab = True
else:
dic[tab_name] =ScriptInterface(None,self.ops, self.update_func, self.help_buf)
dic[tab_name] = ScriptInterface(
None, self.ops, self.update_func, self.help_buf)
return dic
@@ -518,7 +534,8 @@ class OptionList(gtk.ComboBox):
opt, arg = row[0], row[1]
if opt == "":
continue
if (not arg and self.ops[opt]) or (arg and str(self.ops[opt]) == arg):
if ((not arg and self.ops[opt]) or
(arg and str(self.ops[opt]) == arg)):
selected = i
self.set_active(selected)
@@ -535,6 +552,7 @@ class OptionList(gtk.ComboBox):
self.list.append([option, argument, opt])
self.options.append(option)
class OptionCheck(gtk.CheckButton):
def __init__(self, option, label):
opt = label

View File

@@ -123,8 +123,8 @@
# This prints the normal (text) output of a single scan. Ideas for further
# development:
#
# Print the topology graphic. The graphic is already made with Cairo so the same
# code can be used to draw on the print context.
# Print the topology graphic. The graphic is already made with Cairo so the
# same code can be used to draw on the print context.
#
# Print in color with highlighting, like NmapOutputViewer.
#
@@ -139,6 +139,7 @@ import pango
MONOSPACE_FONT_DESC = pango.FontDescription("Monospace 12")
class PrintState (object):
"""This is the userdatum passed to gtk.PrintOperation callbacks."""
@@ -169,7 +170,9 @@ class PrintState (object):
op.set_n_pages((len(self.lines) - 1) / self.lines_per_page + 1)
def draw_page(self, op, context, page_nr):
this_page_lines = self.lines[page_nr * self.lines_per_page:(page_nr + 1) * self.lines_per_page]
this_page_lines = self.lines[
page_nr * self.lines_per_page:
(page_nr + 1) * self.lines_per_page]
layout = context.create_pango_layout()
# Do no wrapping.
layout.set_width(-1)
@@ -180,6 +183,7 @@ class PrintState (object):
cr = context.get_cairo_context()
cr.show_layout(layout)
def run_print_operation(inventory, entry):
op = gtk.PrintOperation()
state = PrintState(inventory, entry)

View File

@@ -125,6 +125,7 @@ import gtk
from zenmapCore.UmitConf import CommandProfile
import zenmapCore.I18N
class ProfileCombo(gtk.ComboBoxEntry, object):
def __init__(self):
gtk.ComboBoxEntry.__init__(self, gtk.ListStore(str), 0)

View File

@@ -123,7 +123,8 @@
import gtk
from zenmapGUI.higwidgets.higwindows import HIGWindow
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox, HIGSpacer, hig_box_space_holder
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox, HIGSpacer, \
hig_box_space_holder
from zenmapGUI.higwidgets.higlabels import HIGSectionLabel, HIGEntryLabel
from zenmapGUI.higwidgets.higscrollers import HIGScrolledWindow
from zenmapGUI.higwidgets.higtextviewers import HIGTextView
@@ -137,8 +138,10 @@ from zenmapCore.UmitLogging import log
import zenmapCore.I18N
from zenmapCore.NmapOptions import NmapOptions
class ProfileEditor(HIGWindow):
def __init__(self, command=None, profile_name=None, deletable=True, overwrite=False):
def __init__(self, command=None, profile_name=None,
deletable=True, overwrite=False):
HIGWindow.__init__(self)
self.connect("delete_event", self.exit)
self.set_title(_('Profile Editor'))
@@ -148,8 +151,8 @@ class ProfileEditor(HIGWindow):
self.profile_name = profile_name
self.overwrite = overwrite
# Used to block recursive updating of the command entry when the command
# entry causes the OptionBuilder widgets to change.
# Used to block recursive updating of the command entry when the
# command entry causes the OptionBuilder widgets to change.
self.inhibit_command_update = False
self.__create_widgets()
@@ -164,20 +167,27 @@ class ProfileEditor(HIGWindow):
# Interface settings
self.profile_name_entry.set_text(profile_name)
self.profile_description_text.get_buffer().set_text(prof['description'])
self.profile_description_text.get_buffer().set_text(
prof['description'])
command_string = prof['command']
self.ops.parse_string(command_string)
if command:
self.ops.parse_string(command)
self.option_builder = OptionBuilder(Path.profile_editor, self.ops, self.update_command, self.help_field.get_buffer())
self.option_builder = OptionBuilder(
Path.profile_editor, self.ops,
self.update_command, self.help_field.get_buffer())
log.debug("Option groups: %s" % str(self.option_builder.groups))
log.debug("Option section names: %s" % str(self.option_builder.section_names))
log.debug("Option section names: %s" % str(
self.option_builder.section_names))
#log.debug("Option tabs: %s" % str(self.option_builder.tabs))
for tab in self.option_builder.groups:
self.__create_tab(_(tab), _(self.option_builder.section_names[tab]), self.option_builder.tabs[tab])
self.__create_tab(
_(tab),
_(self.option_builder.section_names[tab]),
self.option_builder.tabs[tab])
self.update_command()
@@ -195,16 +205,18 @@ class ProfileEditor(HIGWindow):
# cause a change in the command entry.
self.command_entry.handler_block(self.command_entry_changed_cb_id)
self.command_entry.set_text(self.ops.render_string())
self.command_entry.handler_unblock(self.command_entry_changed_cb_id)
self.command_entry.handler_unblock(
self.command_entry_changed_cb_id)
def update_help_name(self, widget, extra):
self.help_field.get_buffer().set_text("Profile name\n\nThis is how the"
+" profile will be identified in the drop-down combo box in the"
+" scan tab.")
self.help_field.get_buffer().set_text(
"Profile name\n\nThis is how the profile will be identified "
"in the drop-down combo box in the scan tab.")
def update_help_desc(self, widget, extra):
self.help_field.get_buffer().set_text("Description\n\nThe description is a"
+ " full description of what the scan does, which may be long.")
self.help_field.get_buffer().set_text(
"Description\n\nThe description is a full description of what "
"the scan does, which may be long.")
def __create_widgets(self):
@@ -218,8 +230,8 @@ class ProfileEditor(HIGWindow):
#self.main_vbox = HIGVBox()
self.command_entry = gtk.Entry()
self.command_entry_changed_cb_id = \
self.command_entry.connect("changed", self.command_entry_changed_cb)
self.command_entry_changed_cb_id = self.command_entry.connect(
"changed", self.command_entry_changed_cb)
self.scan_button = HIGButton(_("Scan"))
self.scan_button.connect("clicked", self.run_scan)
@@ -231,12 +243,14 @@ class ProfileEditor(HIGWindow):
self.profile_info_label = HIGSectionLabel(_('Profile Information'))
self.profile_name_label = HIGEntryLabel(_('Profile name'))
self.profile_name_entry = gtk.Entry()
self.profile_name_entry.connect('enter-notify-event', self.update_help_name)
self.profile_name_entry.connect(
'enter-notify-event', self.update_help_name)
self.profile_description_label = HIGEntryLabel(_('Description'))
self.profile_description_scroll = HIGScrolledWindow()
self.profile_description_scroll.set_border_width(0)
self.profile_description_text = HIGTextView()
self.profile_description_text.connect('motion-notify-event', self.update_help_desc)
self.profile_description_text.connect(
'motion-notify-event', self.update_help_desc)
# Buttons
self.buttons_hbox = HIGHBox()
@@ -259,8 +273,9 @@ class ProfileEditor(HIGWindow):
self.help_field.set_cursor_visible(False)
self.help_field.set_left_margin(5)
self.help_field.set_editable(False)
self.help_vbox.set_size_request(200,-1)
self.help_vbox.set_size_request(200, -1)
###
def __pack_widgets(self):
###
@@ -283,9 +298,9 @@ class ProfileEditor(HIGWindow):
self.main_whole_box._pack_noexpand_nofill(self.lower_box)
###
# Packing profile information tab on notebook
self.notebook.append_page(self.profile_info_vbox, gtk.Label(_('Profile')))
self.notebook.append_page(
self.profile_info_vbox, gtk.Label(_('Profile')))
self.profile_info_vbox.set_border_width(5)
table = HIGTable()
self.profile_info_vbox._pack_noexpand_nofill(self.profile_info_label)
@@ -300,10 +315,11 @@ class ProfileEditor(HIGWindow):
vbox_ann = HIGVBox()
vbox_ann._pack_expand_fill(hig_box_space_holder())
table.attach(self.profile_name_label,0,1,0,1,xoptions=0,yoptions=0)
table.attach(self.profile_name_entry,1,2,0,1,yoptions=0)
table.attach(vbox_desc,0,1,1,2,xoptions=0)
table.attach(self.profile_description_scroll,1,2,1,2)
table.attach(
self.profile_name_label, 0, 1, 0, 1, xoptions=0, yoptions=0)
table.attach(self.profile_name_entry, 1, 2, 0, 1, yoptions=0)
table.attach(vbox_desc, 0, 1, 1, 2, xoptions=0)
table.attach(self.profile_description_scroll, 1, 2, 1, 2)
# Packing buttons on button_hbox
self.buttons_hbox._pack_expand_fill(hig_box_space_holder())
@@ -327,7 +343,7 @@ class ProfileEditor(HIGWindow):
log.debug(">>> Tab name: %s" % tab_name)
log.debug(">>>Creating profile editor section: %s" % section_name)
vbox = HIGVBox()
if tab.notscripttab: # if notscripttab is set
if tab.notscripttab: # if notscripttab is set
table = HIGTable()
table.set_row_spacings(2)
section = HIGSectionLabel(section_name)
@@ -337,7 +353,7 @@ class ProfileEditor(HIGWindow):
tab.fill_table(table, True)
else:
hbox = tab.get_hmain_box()
vbox.pack_start(hbox,True,True,0)
vbox.pack_start(hbox, True, True, 0)
self.notebook.append_page(vbox, gtk.Label(tab_name))
def save_profile(self, widget):
@@ -345,9 +361,10 @@ class ProfileEditor(HIGWindow):
self.profile.remove_profile(self.profile_name)
profile_name = self.profile_name_entry.get_text()
if profile_name == '':
alert = HIGAlertDialog(message_format=_('Unnamed profile'),\
secondary_text=_('You must provide a name \
for this profile.'))
alert = HIGAlertDialog(
message_format=_('Unnamed profile'),
secondary_text=_(
'You must provide a name for this profile.'))
alert.run()
alert.destroy()
@@ -366,11 +383,12 @@ for this profile.'))
command=command,\
description=description)
except ValueError:
alert = HIGAlertDialog(message_format=_('Disallowed profile name'),\
secondary_text=_('Sorry, the name "%s" \
is not allowed due to technical limitations. (The underlying ConfigParser \
used to store profiles does not allow it.) Choose a different \
name.' % profile_name))
alert = HIGAlertDialog(
message_format=_('Disallowed profile name'),
secondary_text=_('Sorry, the name "%s" is not allowed due '
'to technical limitations. (The underlying '
'ConfigParser used to store profiles does not allow '
'it.) Choose a different name.' % profile_name))
alert.run()
alert.destroy()
return
@@ -392,9 +410,10 @@ name.' % profile_name))
if self.deletable:
dialog = HIGDialog(buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
alert = HIGEntryLabel('<b>'+_("Deleting Profile")+'</b>')
text = HIGEntryLabel(_('Your profile is going to be deleted! Click\
Ok to continue, or Cancel to go back to Profile Editor.'))
alert = HIGEntryLabel('<b>' + _("Deleting Profile") + '</b>')
text = HIGEntryLabel(_(
'Your profile is going to be deleted! ClickOk to continue, '
'or Cancel to go back to Profile Editor.'))
hbox = HIGHBox()
hbox.set_border_width(5)
hbox.set_spacing(12)
@@ -404,7 +423,8 @@ name.' % profile_name))
vbox.set_spacing(12)
image = gtk.Image()
image.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG)
image.set_from_stock(
gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG)
vbox.pack_start(alert)
vbox.pack_start(text)
@@ -433,7 +453,7 @@ name.' % profile_name))
self.scan_interface.toolbar.profile_entry.update()
list = self.scan_interface.toolbar.profile_entry.get_model()
length = len(list)
if length >0 :
if length > 0:
self.scan_interface.toolbar.profile_entry.set_active(0)

View File

@@ -122,6 +122,7 @@
from zenmapCore.UmitLogging import log
class ProfileHelp:
def __init__(self, currentstate=None):
self.currentstate = "Default"
@@ -139,7 +140,7 @@ class ProfileHelp:
if self.currentstate in self.labels.keys():
return self.labels[self.currentstate]
else:
return "" #blank
return "" # blank
def add_shortdesc(self, option_name, text):
self.descs[option_name] = text
@@ -148,7 +149,7 @@ class ProfileHelp:
if self.currentstate in self.descs.keys():
return self.descs[self.currentstate]
else:
return "" #blank
return "" # blank
def add_example(self, option_name, text):
self.examples[option_name] = text
@@ -157,8 +158,8 @@ class ProfileHelp:
if self.currentstate in self.examples.keys():
return self.examples[self.currentstate]
else:
return "" #blank
return "" # blank
def handler(self,whichLabel):
def handler(self, whichLabel):
log.debug("whichLabel: %s" % whichLabel)
self.currentstate = whichLabel

View File

@@ -123,7 +123,8 @@
import gtk
from zenmapGUI.higwidgets.higexpanders import HIGExpander
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox, hig_box_space_holder
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox,\
hig_box_space_holder
from zenmapGUI.higwidgets.higlabels import HIGEntryLabel
from zenmapGUI.higwidgets.higtables import HIGTable
from zenmapGUI.Icons import get_os_logo, get_vulnerability_logo
@@ -132,6 +133,7 @@ import zenmapCore.I18N
na = _('Not available')
class ScanHostDetailsPage(HIGExpander):
def __init__(self, host):
HIGExpander.__init__(self, host.get_hostname())
@@ -139,6 +141,7 @@ class ScanHostDetailsPage(HIGExpander):
self.host_details = HostDetails(host)
self.hbox._pack_expand_fill(self.host_details)
class HostDetails(HIGVBox):
def __init__(self, host):
HIGVBox.__init__(self)
@@ -147,7 +150,8 @@ class HostDetails(HIGVBox):
self.set_os_image(get_os_logo(host))
self.set_vulnerability_image(get_vulnerability_logo(host.get_open_ports()))
self.set_vulnerability_image(
get_vulnerability_logo(host.get_open_ports()))
self.set_host_status({'state': host.get_state(),
'open': str(host.get_open_ports()),
@@ -179,16 +183,19 @@ class HostDetails(HIGVBox):
self.set_comment(host.comment)
def __create_widgets(self):
self.host_status_expander = gtk.Expander('<b>'+_('Host Status')+'</b>')
self.address_expander = gtk.Expander('<b>'+_('Addresses')+'</b>')
self.hostnames_expander = gtk.Expander('<b>'+_('Hostnames')+'</b>')
self.os_expander = gtk.Expander('<b>'+_('Operating System')+'</b>')
self.portsused_expander = gtk.Expander('<b>'+_('Ports used')+'</b>')
self.osclass_expander = gtk.Expander('<b>'+_('OS Classes')+'</b>')
self.tcp_expander = gtk.Expander('<b>'+_('TCP Sequence')+'</b>')
self.ip_expander = gtk.Expander('<b>'+_('IP ID Sequence')+'</b>')
self.tcpts_expander = gtk.Expander('<b>'+_('TCP TS Sequence')+'</b>')
self.comment_expander = gtk.Expander('<b>'+_('Comments')+'</b>')
self.host_status_expander = gtk.Expander(
'<b>' + _('Host Status') + '</b>')
self.address_expander = gtk.Expander('<b>' + _('Addresses') + '</b>')
self.hostnames_expander = gtk.Expander('<b>' + _('Hostnames') + '</b>')
self.os_expander = gtk.Expander('<b>' + _('Operating System') + '</b>')
self.portsused_expander = gtk.Expander(
'<b>' + _('Ports used') + '</b>')
self.osclass_expander = gtk.Expander('<b>' + _('OS Classes') + '</b>')
self.tcp_expander = gtk.Expander('<b>' + _('TCP Sequence') + '</b>')
self.ip_expander = gtk.Expander('<b>' + _('IP ID Sequence') + '</b>')
self.tcpts_expander = gtk.Expander(
'<b>' + _('TCP TS Sequence') + '</b>')
self.comment_expander = gtk.Expander('<b>' + _('Comments') + '</b>')
self.os_image = gtk.Image()
self.vulnerability_image = gtk.Image()
@@ -214,7 +221,6 @@ class HostDetails(HIGVBox):
self.lastboot_label = HIGEntryLabel(_('Last boot:'))
self.info_lastboot_label = HIGEntryLabel(na)
# Addresses expander
self.ipv4_label = HIGEntryLabel(_('IPv4:'))
self.info_ipv4_label = HIGEntryLabel(na)
@@ -243,63 +249,78 @@ class HostDetails(HIGVBox):
table, hbox = self.create_table_hbox()
try:
if status['state'] == '': raise Exception
if status['state'] == '':
raise Exception
self.info_host_state_label.set_text(status['state'])
except:pass
except:
pass
try:
if status['open'] == '': raise Exception
if status['open'] == '':
raise Exception
self.info_open_ports.set_text(status['open'])
except:pass
except:
pass
try:
if status['filtered'] == '': raise Exception
if status['filtered'] == '':
raise Exception
self.info_filtered_label.set_text(status['filtered'])
except:pass
except:
pass
try:
if status['closed'] == '': raise Exception
if status['closed'] == '':
raise Exception
self.info_closed_ports.set_text(status['closed'])
except:pass
except:
pass
try:
if status['scanned'] == '': raise Exception
if status['scanned'] == '':
raise Exception
self.info_scanned_label.set_text(status['scanned'])
except:pass
except:
pass
try:
if status['uptime'] == '': raise Exception
if status['uptime'] == '':
raise Exception
self.info_uptime_label.set_text(status['uptime'])
except:pass
except:
pass
try:
if status['lastboot'] == '': raise Exception
if status['lastboot'] == '':
raise Exception
self.info_lastboot_label.set_text(status['lastboot'])
except:pass
except:
pass
table.attach(self.host_state_label,0,1,0,1)
table.attach(self.info_host_state_label,1,2,0,1)
table.attach(self.host_state_label, 0, 1, 0, 1)
table.attach(self.info_host_state_label, 1, 2, 0, 1)
table.attach(self.open_label,0,1,1,2)
table.attach(self.info_open_ports,1,2,1,2)
table.attach(self.open_label, 0, 1, 1, 2)
table.attach(self.info_open_ports, 1, 2, 1, 2)
table.attach(self.filtered_label,0,1,2,3)
table.attach(self.info_filtered_label,1,2,2,3)
table.attach(self.filtered_label, 0, 1, 2, 3)
table.attach(self.info_filtered_label, 1, 2, 2, 3)
table.attach(self.closed_label,0,1,3,4)
table.attach(self.info_closed_ports,1,2,3,4)
table.attach(self.closed_label, 0, 1, 3, 4)
table.attach(self.info_closed_ports, 1, 2, 3, 4)
table.attach(self.scanned_label,0,1,4,5)
table.attach(self.info_scanned_label,1,2,4,5)
table.attach(self.scanned_label, 0, 1, 4, 5)
table.attach(self.info_scanned_label, 1, 2, 4, 5)
table.attach(self.uptime_label,0,1,5,6)
table.attach(self.info_uptime_label,1,2,5,6)
table.attach(self.uptime_label, 0, 1, 5, 6)
table.attach(self.info_uptime_label, 1, 2, 5, 6)
table.attach(self.lastboot_label,0,1,6,7)
table.attach(self.info_lastboot_label,1,2,6,7)
table.attach(self.lastboot_label, 0, 1, 6, 7)
table.attach(self.info_lastboot_label, 1, 2, 6, 7)
table.attach(self.os_image,2,4,0,3,xoptions=1,yoptions=0)
table.attach(self.vulnerability_image,2,4,4,7,xoptions=1,yoptions=0)
table.attach(self.os_image, 2, 4, 0, 3, xoptions=1, yoptions=0)
table.attach(
self.vulnerability_image, 2, 4, 4, 7, xoptions=1, yoptions=0)
table.set_col_spacing(1, 50)
@@ -307,10 +328,10 @@ class HostDetails(HIGVBox):
self._pack_noexpand_nofill(self.host_status_expander)
def set_os_image(self, image):
self.os_image.set_from_stock(image,gtk.ICON_SIZE_DIALOG)
self.os_image.set_from_stock(image, gtk.ICON_SIZE_DIALOG)
def set_vulnerability_image(self, image):
self.vulnerability_image.set_from_stock(image,gtk.ICON_SIZE_DIALOG)
self.vulnerability_image.set_from_stock(image, gtk.ICON_SIZE_DIALOG)
def set_addresses(self, address):
self.address_expander.set_use_markup(True)
@@ -319,28 +340,34 @@ class HostDetails(HIGVBox):
#print '>>> Address:', address
try:
if address['ipv4'] == 1: raise Exception
if address['ipv4'] == 1:
raise Exception
self.info_ipv4_label.set_text(address['ipv4'])
except:pass
except:
pass
try:
if address['ipv6'] == 1: raise Exception
if address['ipv6'] == 1:
raise Exception
self.info_ipv6_label.set_text(address['ipv6'])
except:pass
except:
pass
try:
if address['mac'] == 1: raise Exception
if address['mac'] == 1:
raise Exception
self.info_mac_label.set_text(address['mac'])
except:pass
except:
pass
table.attach(self.ipv4_label,0,1,0,1)
table.attach(self.info_ipv4_label,1,2,0,1)
table.attach(self.ipv4_label, 0, 1, 0, 1)
table.attach(self.info_ipv4_label, 1, 2, 0, 1)
table.attach(self.ipv6_label,0,1,1,2)
table.attach(self.info_ipv6_label,1,2,1,2)
table.attach(self.ipv6_label, 0, 1, 1, 2)
table.attach(self.info_ipv6_label, 1, 2, 1, 2)
table.attach(self.mac_label,0,1,2,3)
table.attach(self.info_mac_label,1,2,2,3)
table.attach(self.mac_label, 0, 1, 2, 3)
table.attach(self.info_mac_label, 1, 2, 2, 3)
self.address_expander.add(hbox)
self._pack_noexpand_nofill(self.address_expander)
@@ -356,17 +383,21 @@ class HostDetails(HIGVBox):
for h in hostname:
name = na
try:name = h['hostname']
except:pass
try:
name = h['hostname']
except:
pass
type = na
try:type = h['hostname_type']
except:pass
try:
type = h['hostname_type']
except:
pass
table.attach(HIGEntryLabel(_('Name - Type:')),0,1,y1,y2)
table.attach(HIGEntryLabel(name+' - '+\
type),1,2,y1,y2)
y1+=1;y2+=1
table.attach(HIGEntryLabel(_('Name - Type:')), 0, 1, y1, y2)
table.attach(HIGEntryLabel(name + ' - ' + type), 1, 2, y1, y2)
y1 += 1
y2 += 1
self.hostnames_expander.add(hbox)
self._pack_noexpand_nofill(self.hostnames_expander)
@@ -379,29 +410,34 @@ class HostDetails(HIGVBox):
progress = gtk.ProgressBar()
try:
progress.set_fraction(float(os['accuracy'])/100.0)
progress.set_text(os['accuracy']+'%')
except:progress.set_text(_('Not Available'))
progress.set_fraction(float(os['accuracy']) / 100.0)
progress.set_text(os['accuracy'] + '%')
except:
progress.set_text(_('Not Available'))
table.attach(HIGEntryLabel(_('Name:')),0,1,0,1)
table.attach(HIGEntryLabel(os['name']),1,2,0,1)
table.attach(HIGEntryLabel(_('Name:')), 0, 1, 0, 1)
table.attach(HIGEntryLabel(os['name']), 1, 2, 0, 1)
table.attach(HIGEntryLabel(_('Accuracy:')),0,1,1,2)
table.attach(progress,1,2,1,2)
table.attach(HIGEntryLabel(_('Accuracy:')), 0, 1, 1, 2)
table.attach(progress, 1, 2, 1, 2)
y1=2;y2=3
y1 = 2
y2 = 3
try:
self.set_ports_used(os['portsused'])
table.attach(self.portsused_expander,0,2,y1,y2)
y1+=1;y2+=1
except:pass
table.attach(self.portsused_expander, 0, 2, y1, y2)
y1 += 1
y2 += 1
except:
pass
try:
self.set_osclass(os['osclasses'])
self.osclass_expander.set_use_markup(True)
table.attach(self.osclass_expander,0,2,y1,y2)
except:pass
table.attach(self.osclass_expander, 0, 2, y1, y2)
except:
pass
self.os_expander.add(hbox)
self._pack_noexpand_nofill(self.os_expander)
@@ -410,13 +446,17 @@ class HostDetails(HIGVBox):
self.portsused_expander.set_use_markup(True)
table, hbox = self.create_table_hbox()
y1=0;y2=1
y1 = 0
y2 = 1
for p in ports:
table.attach(HIGEntryLabel(_('Port-Protocol-State:')),0,1,y1,y2)
table.attach(HIGEntryLabel(p['portid']+' - '+p['proto']+' - '+\
p['state']),1,2,y1,y2)
y1+=1;y2+=1
table.attach(HIGEntryLabel(
_('Port-Protocol-State:')), 0, 1, y1, y2)
table.attach(HIGEntryLabel(
p['portid'] + ' - ' + p['proto'] + ' - ' + p['state']
), 1, 2, y1, y2)
y1 += 1
y2 += 1
self.portsused_expander.add(hbox)
@@ -425,25 +465,27 @@ class HostDetails(HIGVBox):
self.osclass_expander.set_use_markup(True)
table, hbox = self.create_table_hbox()
table.attach(HIGEntryLabel(_('Type')),0,1,0,1)
table.attach(HIGEntryLabel(_('Vendor')),1,2,0,1)
table.attach(HIGEntryLabel(_('OS Family')),2,3,0,1)
table.attach(HIGEntryLabel(_('OS Generation')),3,4,0,1)
table.attach(HIGEntryLabel(_('Accuracy')),4,5,0,1)
table.attach(HIGEntryLabel(_('Type')), 0, 1, 0, 1)
table.attach(HIGEntryLabel(_('Vendor')), 1, 2, 0, 1)
table.attach(HIGEntryLabel(_('OS Family')), 2, 3, 0, 1)
table.attach(HIGEntryLabel(_('OS Generation')), 3, 4, 0, 1)
table.attach(HIGEntryLabel(_('Accuracy')), 4, 5, 0, 1)
y1=1;y2=2
y1 = 1
y2 = 2
for o in osclass:
table.attach(HIGEntryLabel(o['type']),0,1,y1,y2)
table.attach(HIGEntryLabel(o['vendor']),1,2,y1,y2)
table.attach(HIGEntryLabel(o['osfamily']),2,3,y1,y2)
table.attach(HIGEntryLabel(o['osgen']),3,4,y1,y2)
table.attach(HIGEntryLabel(o['type']), 0, 1, y1, y2)
table.attach(HIGEntryLabel(o['vendor']), 1, 2, y1, y2)
table.attach(HIGEntryLabel(o['osfamily']), 2, 3, y1, y2)
table.attach(HIGEntryLabel(o['osgen']), 3, 4, y1, y2)
progress = gtk.ProgressBar()
progress.set_text(o['accuracy']+'%')
progress.set_fraction(float(o['accuracy'])/100.0)
table.attach(progress,4,5,y1,y2)
y1+=1;y2+=1
progress.set_text(o['accuracy'] + '%')
progress.set_fraction(float(o['accuracy']) / 100.0)
table.attach(progress, 4, 5, y1, y2)
y1 += 1
y2 += 1
self.osclass_expander.add(hbox)
@@ -456,14 +498,14 @@ class HostDetails(HIGVBox):
for v in tcpseq['values'].split(','):
combo.append_text(v)
table.attach(HIGEntryLabel(_('Difficulty:')),0,1,1,2)
table.attach(HIGEntryLabel(tcpseq['difficulty']),1,2,1,2)
table.attach(HIGEntryLabel(_('Difficulty:')), 0, 1, 1, 2)
table.attach(HIGEntryLabel(tcpseq['difficulty']), 1, 2, 1, 2)
table.attach(HIGEntryLabel(_('Index:')),0,1,2,3)
table.attach(HIGEntryLabel(tcpseq['index']),1,2,2,3)
table.attach(HIGEntryLabel(_('Index:')), 0, 1, 2, 3)
table.attach(HIGEntryLabel(tcpseq['index']), 1, 2, 2, 3)
table.attach(HIGEntryLabel(_('Values:')),0,1,3,4)
table.attach(combo,1,2,3,4)
table.attach(HIGEntryLabel(_('Values:')), 0, 1, 3, 4)
table.attach(combo, 1, 2, 3, 4)
self.tcp_expander.add(hbox)
self._pack_noexpand_nofill(self.tcp_expander)
@@ -478,11 +520,11 @@ class HostDetails(HIGVBox):
for i in ipseq['values'].split(','):
combo.append_text(i)
table.attach(HIGEntryLabel(_('Class:')),0,1,0,1)
table.attach(HIGEntryLabel(ipseq['class']),1,2,0,1)
table.attach(HIGEntryLabel(_('Class:')), 0, 1, 0, 1)
table.attach(HIGEntryLabel(ipseq['class']), 1, 2, 0, 1)
table.attach(HIGEntryLabel(_('Values:')),0,1,1,2)
table.attach(combo,1,2,1,2)
table.attach(HIGEntryLabel(_('Values:')), 0, 1, 1, 2)
table.attach(combo, 1, 2, 1, 2)
self.ip_expander.add(hbox)
self._pack_noexpand_nofill(self.ip_expander)
@@ -497,11 +539,11 @@ class HostDetails(HIGVBox):
for i in tcptsseq['values'].split(','):
combo.append_text(i)
table.attach(HIGEntryLabel(_('Class:')),0,1,0,1)
table.attach(HIGEntryLabel(tcptsseq['class']),1,2,0,1)
table.attach(HIGEntryLabel(_('Class:')), 0, 1, 0, 1)
table.attach(HIGEntryLabel(tcptsseq['class']), 1, 2, 0, 1)
table.attach(HIGEntryLabel(_('Values:')),0,1,1,2)
table.attach(combo,1,2,1,2)
table.attach(HIGEntryLabel(_('Values:')), 0, 1, 1, 2)
table.attach(combo, 1, 2, 1, 2)
self.tcpts_expander.add(hbox)
self._pack_noexpand_nofill(self.tcpts_expander)
@@ -515,8 +557,8 @@ class HostDetails(HIGVBox):
self.comment_scrolled = gtk.ScrolledWindow()
self.comment_scrolled.set_border_width(5)
self.comment_scrolled.set_policy(gtk.POLICY_AUTOMATIC,\
gtk.POLICY_AUTOMATIC)
self.comment_scrolled.set_policy(
gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.comment_txt_vw = gtk.TextView()
self.comment_txt_vw.set_wrap_mode(gtk.WRAP_WORD)

View File

@@ -127,16 +127,19 @@ from zenmapGUI.higwidgets.higboxes import HIGVBox
from zenmapGUI.Icons import get_os_icon
import zenmapCore.I18N
def treemodel_get_addrs_for_sort(model, iter):
host = model.get_value(iter, 0)
return host.get_addrs_for_sort()
# Used to sort hosts by address.
def cmp_treemodel_addr(model, iter_a, iter_b):
addrs_a = treemodel_get_addrs_for_sort(model, iter_a)
addrs_b = treemodel_get_addrs_for_sort(model, iter_b)
return cmp(addrs_a, addrs_b)
class ScanHostsView(HIGVBox, object):
HOST_MODE, SERVICE_MODE = range(2)
@@ -272,8 +275,8 @@ class ScanHostsView(HIGVBox, object):
self.host_column.pack_start(self.host_cell, True)
self.pic_column.set_min_width(35)
self.pic_column.set_attributes(self.os_cell, stock_id = 1)
self.host_column.set_attributes(self.host_cell, text = 2)
self.pic_column.set_attributes(self.os_cell, stock_id=1)
self.host_column.set_attributes(self.host_cell, text=2)
def mass_update(self, hosts):
"""Update the internal ListStores to reflect the hosts and services

View File

@@ -145,7 +145,8 @@ from zenmapGUI.ScanScanListPage import ScanScanListPage
from zenmapGUI.ScansListStore import ScansListStore
from zenmapGUI.TopologyPage import TopologyPage
from zenmapCore.NetworkInventory import NetworkInventory, FilteredNetworkInventory
from zenmapCore.NetworkInventory import NetworkInventory,\
FilteredNetworkInventory
from zenmapCore.NmapCommand import NmapCommand
from zenmapCore.UmitConf import CommandProfile, ProfileNotFound, is_maemo
from zenmapCore.NmapParser import NmapParser
@@ -157,6 +158,7 @@ import zenmapCore.I18N
# How often the live output view refreshes, in milliseconds.
NMAP_OUTPUT_REFRESH_INTERVAL = 1000
class ScanInterface(HIGVBox):
"""ScanInterface contains the scan toolbar and the scan results. Each
ScanInterface represents a single NetworkInventory as well as a set of
@@ -204,20 +206,26 @@ class ScanInterface(HIGVBox):
scan_interface=self)
self.host_view_selection = self.scan_result.get_host_selection()
self.service_view_selection = self.scan_result.get_service_selection()
self.host_view_selection.connect('changed', self.host_selection_changed)
self.service_view_selection.connect('changed', self.service_selection_changed)
self.host_view_selection.connect(
'changed', self.host_selection_changed)
self.service_view_selection.connect(
'changed', self.service_selection_changed)
host_page = self.scan_result.scan_result_notebook.open_ports.host
host_page.host_view.get_selection().connect('changed', self.service_host_selection_changed)
self.host_view_selection.connect('changed', self.host_selection_changed)
host_page.host_view.get_selection().connect(
'changed', self.service_host_selection_changed)
self.host_view_selection.connect(
'changed', self.host_selection_changed)
self.scan_result.scan_result_notebook.nmap_output.connect("changed", self._displayed_scan_change_cb)
self.scan_result.scan_result_notebook.scans_list.remove_button.connect("clicked", self._remove_scan_cb)
self.scan_result.scan_result_notebook.nmap_output.connect(
"changed", self._displayed_scan_change_cb)
self.scan_result.scan_result_notebook.scans_list.remove_button.connect(
"clicked", self._remove_scan_cb)
# The hosts dict maps hostnames (as returned by HostInfo.get_hostname)
# to HostInfo objects.
self.hosts = {}
# The services dict maps service names ("http") to lists of dicts of the
# form
# The services dict maps service names ("http") to lists of dicts of
# the form
# {'host': <HostInfo object>, 'hostname': u'example.com',
# 'port_state': u'open', 'portid': u'22', 'protocol': u'tcp',
# 'service_conf': u'10', 'service_extrainfo': u'protocol 2.0',
@@ -236,7 +244,8 @@ class ScanInterface(HIGVBox):
self._pack_noexpand_nofill(self.top_box)
self._pack_expand_fill(self.scan_result)
self.scan_result.scan_result_notebook.scans_list.cancel_button.connect("clicked", self._cancel_scans_list_cb)
self.scan_result.scan_result_notebook.scans_list.cancel_button.connect(
"clicked", self._cancel_scans_list_cb)
self.update_cancel_button()
# Create the filter GUI
@@ -271,16 +280,18 @@ class ScanInterface(HIGVBox):
# Restart the timer to start the filter.
if self.filter_timeout_id:
gobject.source_remove(self.filter_timeout_id)
self.filter_timeout_id = gobject.timeout_add(self.FILTER_DELAY, self.filter_hosts, filter_bar.get_filter_string())
self.filter_timeout_id = gobject.timeout_add(
self.FILTER_DELAY, self.filter_hosts,
filter_bar.get_filter_string())
def filter_hosts(self, filter_string):
start = time.clock()
self.inventory.apply_filter(filter_string)
filter_time = time.clock() - start;
filter_time = time.clock() - start
# Update the gui
start = time.clock()
self.update_ui()
gui_time = time.clock() - start;
gui_time = time.clock() - start
if filter_time + gui_time > 0.0:
log.debug("apply_filter %g ms update_ui %g ms (%.0f%% filter)" %
@@ -302,8 +313,8 @@ class ScanInterface(HIGVBox):
return len(self.jobs)
def select_default_profile(self):
"""Select a "default" profile. Currently this is defined to be the first
profile."""
"""Select a "default" profile. Currently this is defined to be the
first profile."""
if len(self.toolbar.profile_entry.get_model()) > 0:
self.toolbar.profile_entry.set_active(0)
@@ -314,21 +325,22 @@ class ScanInterface(HIGVBox):
def __create_toolbar(self):
self.toolbar = ScanToolbar()
self.target_entry_changed_handler = \
self.toolbar.target_entry.connect('changed', self._target_entry_changed)
self.target_entry_changed_handler = self.toolbar.target_entry.connect(
'changed', self._target_entry_changed)
self.profile_entry_changed_handler = \
self.toolbar.profile_entry.connect('changed', self._profile_entry_changed)
self.toolbar.profile_entry.connect(
'changed', self._profile_entry_changed)
self.toolbar.scan_button.connect('clicked', self.start_scan_cb)
self.toolbar.cancel_button.connect('clicked', self._cancel_scan_cb)
def __create_command_toolbar(self):
self.command_toolbar = ScanCommandToolbar()
self.command_toolbar.command_entry.connect('activate',
lambda x: self.toolbar.scan_button.clicked())
self.command_toolbar.command_entry.connect(
'activate', lambda x: self.toolbar.scan_button.clicked())
self.command_entry_changed_handler = \
self.command_toolbar.command_entry.connect('changed', self._command_entry_changed)
self.command_toolbar.command_entry.connect(
'changed', self._command_entry_changed)
def _command_entry_changed(self, editable):
ops = NmapOptions()
@@ -378,23 +390,29 @@ class ScanInterface(HIGVBox):
def set_command_quiet(self, command_string):
"""Set the command used by this scan interface, ignoring any further
"changed" signals."""
self.command_toolbar.command_entry.handler_block(self.command_entry_changed_handler)
self.command_toolbar.command_entry.handler_block(
self.command_entry_changed_handler)
self.command_toolbar.set_command(command_string)
self.command_toolbar.command_entry.handler_unblock(self.command_entry_changed_handler)
self.command_toolbar.command_entry.handler_unblock(
self.command_entry_changed_handler)
def set_target_quiet(self, target_string):
"""Set the target string used by this scan interface, ignoring any
further "changed" signals."""
self.toolbar.target_entry.handler_block(self.target_entry_changed_handler)
self.toolbar.target_entry.handler_block(
self.target_entry_changed_handler)
self.toolbar.set_selected_target(target_string)
self.toolbar.target_entry.handler_unblock(self.target_entry_changed_handler)
self.toolbar.target_entry.handler_unblock(
self.target_entry_changed_handler)
def set_profile_name_quiet(self, profile_name):
"""Set the profile name used by this scan interface, ignoring any
further "changed" signals."""
self.toolbar.profile_entry.handler_block(self.profile_entry_changed_handler)
self.toolbar.profile_entry.handler_block(
self.profile_entry_changed_handler)
self.toolbar.set_selected_profile(profile_name)
self.toolbar.profile_entry.handler_unblock(self.profile_entry_changed_handler)
self.toolbar.profile_entry.handler_unblock(
self.profile_entry_changed_handler)
def start_scan_cb(self, widget=None):
target = self.toolbar.selected_target
@@ -412,14 +430,17 @@ class ScanInterface(HIGVBox):
except IOError, e:
# We failed to save target_list.txt; treat it as read-only.
# Probably it's owned by root and this is a normal user.
log.debug(">>> Error saving %s: %s" % (Path.target_list, str(e)))
log.debug(">>> Error saving %s: %s" % (
Path.target_list, str(e)))
if command == '':
warn_dialog = HIGAlertDialog(message_format=_("Empty Nmap Command"),
secondary_text=_("There is no command to \
execute. Maybe the selected/typed profile doesn't exist. Please, check the profile name \
or type the nmap command you would like to execute."),
type=gtk.MESSAGE_ERROR)
warn_dialog = HIGAlertDialog(
message_format=_("Empty Nmap Command"),
secondary_text=_("There is no command to execute. "
"Maybe the selected/typed profile doesn't exist. "
"Please check the profile name or type the nmap "
"command you would like to execute."),
type=gtk.MESSAGE_ERROR)
warn_dialog.run()
warn_dialog.destroy()
return
@@ -467,8 +488,8 @@ or type the nmap command you would like to execute."),
self.inventory.remove_scan(entry.parsed)
except ValueError:
pass
# Create TreeRowReferences because those persist while we change the
# model.
# Create TreeRowReferences because those persist while we change
# the model.
selected_refs.append(gtk.TreeRowReference(model, path))
# Delete the entries from the ScansListStore.
for ref in selected_refs:
@@ -500,7 +521,7 @@ or type the nmap command you would like to execute."),
self.jobs.remove(command)
self.update_cancel_button()
def execute_command(self, command, target = None, profile = None):
def execute_command(self, command, target=None, profile=None):
"""Run the given Nmap command. Add it to the list of running scans.
Schedule a timer to refresh the output and check the scan for
completion."""
@@ -515,21 +536,27 @@ or type the nmap command you would like to execute."),
# Handle ENOENT specially.
if e.errno == errno.ENOENT:
# nmap_command_path comes from zenmapCore.NmapCommand.
text += "\n\n" + _("This means that the nmap executable was not found in your system PATH, which is") + "\n\n" + os.getenv("PATH", _("<undefined>"))
text += "\n\n%s\n\n%s" % (
_("This means that the nmap executable was "
"not found in your system PATH, which is"),
os.getenv("PATH", _("<undefined>"))
)
path_env = os.getenv("PATH")
if path_env is None:
default_paths = []
else:
default_paths = path_env.split(os.pathsep)
extra_paths = get_extra_executable_search_paths()
extra_paths = [p for p in extra_paths if p not in default_paths]
extra_paths = [p for p in extra_paths if (
p not in default_paths)]
if len(extra_paths) > 0:
if len(extra_paths) == 1:
text += "\n\n" + _("plus the extra directory")
else:
text += "\n\n" + _("plus the extra directories")
text += "\n\n" + os.pathsep.join(extra_paths)
warn_dialog = HIGAlertDialog(message_format=_("Error executing command"),
warn_dialog = HIGAlertDialog(
message_format=_("Error executing command"),
secondary_text=text, type=gtk.MESSAGE_ERROR)
warn_dialog.run()
warn_dialog.destroy()
@@ -546,7 +573,8 @@ or type the nmap command you would like to execute."),
self.scan_result.refresh_nmap_output()
# Add a timeout function
self.verify_thread_timeout_id = gobject.timeout_add(NMAP_OUTPUT_REFRESH_INTERVAL, self.verify_execution)
self.verify_thread_timeout_id = gobject.timeout_add(
NMAP_OUTPUT_REFRESH_INTERVAL, self.verify_execution)
def verify_execution(self):
"""This is a callback that is called periodically to refresh the output
@@ -597,12 +625,12 @@ or type the nmap command you would like to execute."),
except:
st = None
if st is None or st.st_size > 0:
warn_dialog = HIGAlertDialog(message_format = _("Parse error"),
secondary_text = _(u"""\
There was an error while parsing the XML file generated from the scan:
%s\
""") % str(e), type = gtk.MESSAGE_ERROR)
warn_dialog = HIGAlertDialog(
message_format=_("Parse error"),
secondary_text=_(
"There was an error while parsing the XML file "
"generated from the scan:\n\n%s""") % str(e),
type=gtk.MESSAGE_ERROR)
warn_dialog.run()
warn_dialog.destroy()
else:
@@ -612,12 +640,12 @@ There was an error while parsing the XML file generated from the scan:
try:
self.inventory.add_scan(parsed)
except Exception, e:
warn_dialog = HIGAlertDialog(message_format = _("Cannot merge scan"),
secondary_text = _(u"""\
There was an error while merging the new scan's XML:
%s\
""") % str(e), type = gtk.MESSAGE_ERROR)
warn_dialog = HIGAlertDialog(
message_format=_("Cannot merge scan"),
secondary_text=_(
"There was an error while merging the new scan's "
"XML:\n\n%s") % str(e),
type=gtk.MESSAGE_ERROR)
warn_dialog.run()
warn_dialog.destroy()
parsed.set_xml_is_temp(command.xml_is_temp)
@@ -686,27 +714,29 @@ There was an error while merging the new scan's XML:
if name not in self.services.keys():
self.services[name] = []
hs = {"host":host, "hostname":hostname}
hs = {"host": host, "hostname": hostname}
hs.update(service)
self.services[name].append(hs)
self.hosts[hostname] = host
# If the host and service selection is empty or has become empty, select
# the first host if there is at least one.
if len(self.host_view_selection.get_selected_rows()[1]) == 0 \
and len(self.service_view_selection.get_selected_rows()[1]) == 0 \
and len(self.scan_result.scan_host_view.host_list) > 0:
self.host_view_selection.select_iter(self.scan_result.scan_host_view.host_list.get_iter_first())
# If the host and service selection is empty or has become empty,
# select the first host if there is at least one.
if (len(self.service_view_selection.get_selected_rows()[1]) == 0 and
len(self.host_view_selection.get_selected_rows()[1]) == 0 and
len(self.scan_result.scan_host_view.host_list) > 0):
self.host_view_selection.select_iter(
self.scan_result.scan_host_view.host_list.get_iter_first())
self.filter_bar.set_information_text(_("%d/%d hosts shown") %
(len(self.inventory.get_hosts_up()),
len(NetworkInventory.get_hosts_up(self.inventory))))
if self.scan_result.scan_host_view.mode == ScanHostsView.HOST_MODE:
mode = self.scan_result.scan_host_view.mode
if mode == ScanHostsView.HOST_MODE:
self.refresh_port_output()
elif self.scan_result.scan_host_view.mode == ScanHostsView.SERVICE_MODE:
elif mode == ScanHostsView.SERVICE_MODE:
self.refresh_host_output()
def refresh_port_output(self):
@@ -714,11 +744,12 @@ There was an error while merging the new scan's XML:
current host selection."""
self.scan_result.scan_result_notebook.port_mode()
model_host_list, selection = self.host_view_selection.get_selected_rows()
model_host_list, selection = \
self.host_view_selection.get_selected_rows()
host_objs = []
for i in selection:
hostname = model_host_list[i[0]][2]
if self.hosts.has_key(hostname):
if hostname in self.hosts:
host_objs.append(self.hosts[hostname])
if len(host_objs) == 1:
@@ -732,11 +763,12 @@ There was an error while merging the new scan's XML:
current service selection."""
self.scan_result.scan_result_notebook.host_mode()
model_service_list, selection = self.service_view_selection.get_selected_rows()
model_service_list, selection = \
self.service_view_selection.get_selected_rows()
serv_objs = []
for i in selection:
key = model_service_list[i[0]][0]
if self.services.has_key(key):
if key in self.services:
serv_objs.append(self.services[key])
# Each element of serv_objs is a list of port dicts.
@@ -745,7 +777,9 @@ There was an error while merging the new scan's XML:
else:
servs = []
for s in serv_objs:
servs.append({"service_name":s[0]["service_name"], "ports": s})
servs.append({
"service_name": s[0]["service_name"],
"ports": s})
self.set_multiple_service_host(servs)
def host_selection_changed(self, widget):
@@ -791,7 +825,8 @@ There was an error while merging the new scan's XML:
"""Sets the comment on a host from the contents of the comment text
entry."""
buff = widget.get_buffer()
host.comment = buff.get_text(buff.get_start_iter(), buff.get_end_iter())
host.comment = buff.get_text(
buff.get_start_iter(), buff.get_end_iter())
for scan in self.inventory.get_scans():
if host in scan.get_hosts():
scan.unsaved = True
@@ -803,8 +838,10 @@ There was an error while merging the new scan's XML:
pages = []
for host in hosts:
page = ScanHostDetailsPage(host)
page.host_details.comment_txt_vw.connect("insert-at-cursor", self._save_comment, host)
page.host_details.comment_txt_vw.connect("focus-out-event", self._save_comment, host)
page.host_details.comment_txt_vw.connect(
"insert-at-cursor", self._save_comment, host)
page.host_details.comment_txt_vw.connect(
"focus-out-event", self._save_comment, host)
pages.append(page)
return pages
@@ -833,9 +870,9 @@ There was an error while merging the new scan's XML:
host_page.thaw()
def set_multiple_host_port(self, host_list):
"""Change the "Ports / Hosts" tab to show the port output for all of the
hosts in host_list. When multiple hosts are selected, the port output
for each is contained in an expander."""
"""Change the "Ports / Hosts" tab to show the port output for all of
the hosts in host_list. When multiple hosts are selected, the port
output for each is contained in an expander."""
host_page = self.scan_result.scan_result_notebook.open_ports.host
host_page.switch_port_to_tree_store()
@@ -846,19 +883,22 @@ There was an error while merging the new scan's XML:
host_page.thaw()
def set_multiple_service_host(self, service_list):
"""Change the "Ports / Hosts" tab to show the hosts associated with each
of the services in service_list. Each element of service_list must be a
dict with the keys "service_name" and "ports". When multiple services
are selected, the hosts for each are contained in an expander."""
"""Change the "Ports / Hosts" tab to show the hosts associated with
each of the services in service_list. Each element of service_list must
be a dict with the keys "service_name" and "ports". When multiple
services are selected, the hosts for each are contained in an
expander."""
host_page = self.scan_result.scan_result_notebook.open_ports.host
host_page.switch_host_to_tree_store()
host_page.freeze()
host_page.clear_host_tree()
for service in service_list:
host_page.add_to_host_tree(service["service_name"], service["ports"])
host_page.add_to_host_tree(
service["service_name"], service["ports"])
host_page.thaw()
class ScanResult(gtk.HPaned):
"""This is the pane that has the "Host"/"Service" column (ScanHostsView) on
the left and the "Nmap Output"/"Ports / Hosts"/etc. (ScanResultNotebook) on
@@ -915,7 +955,8 @@ class ScanResultNotebook(HIGNotebook):
self.__create_widgets(inventory, scans_store)
self.scans_list.scans_list.connect("row-activated", self._scan_row_activated)
self.scans_list.scans_list.connect(
"row-activated", self._scan_row_activated)
self.append_page(self.nmap_output_page, gtk.Label(_('Nmap Output')))
self.append_page(self.open_ports_page, gtk.Label(_('Ports / Hosts')))

View File

@@ -134,6 +134,7 @@ from zenmapCore.Paths import Path
from zenmapCore.UmitLogging import log
import zenmapCore.I18N
def scan_entry_data_func(widget, cell_renderer, model, iter):
"""Set the properties of a cell renderer for a scan entry."""
cell_renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
@@ -150,12 +151,15 @@ def scan_entry_data_func(widget, cell_renderer, model, iter):
cell_renderer.set_property("strikethrough", True)
cell_renderer.set_property("text", entry.get_command_string())
class Throbber(gtk.Image):
"""This is a little progress indicator that animates while a scan is
running."""
try:
still = gtk.gdk.pixbuf_new_from_file(os.path.join(Path.pixmaps_dir, "throbber.png"))
anim = gtk.gdk.PixbufAnimation(os.path.join(Path.pixmaps_dir, "throbber.gif"))
still = gtk.gdk.pixbuf_new_from_file(
os.path.join(Path.pixmaps_dir, "throbber.png"))
anim = gtk.gdk.PixbufAnimation(
os.path.join(Path.pixmaps_dir, "throbber.gif"))
except Exception, e:
log.debug("Error loading throbber images: %s." % str(e))
still = None
@@ -177,6 +181,7 @@ class Throbber(gtk.Image):
self.set_from_pixbuf(self.still)
self.animating = False
class ScanNmapOutputPage(HIGVBox):
"""This is the "Nmap Output" scan results tab. It holds a text view of Nmap
output. The constructor takes a ScansListStore, the contents of which are
@@ -223,8 +228,8 @@ class ScanNmapOutputPage(HIGVBox):
self._update()
def set_active_iter(self, i):
"""Set the active entry to an interator into the ScansListStore referred
to by this object."""
"""Set the active entry to an interator into the ScansListStore
referred to by this object."""
self.scans_list.set_active_iter(i)
def get_active_entry(self):
@@ -287,9 +292,11 @@ class ScanNmapOutputPage(HIGVBox):
if self._details_windows.get(entry) is None:
window = gtk.Window()
window.add(ScanRunDetailsPage(entry.parsed))
def close_details(details, event, entry):
details.destroy()
del self._details_windows[entry]
window.connect("delete-event", close_details, entry)
window.show_all()
self._details_windows[entry] = window

View File

@@ -128,12 +128,14 @@ from zenmapGUI.higwidgets.higtables import HIGTable
from zenmapCore.UmitLogging import log
import zenmapCore.I18N
def findout_service_icon(port_info):
if port_info["port_state"] in ["open", "open|filtered"]:
return gtk.STOCK_YES
else:
return gtk.STOCK_NO
def get_version_string(d):
"""Get a human-readable version string from the dict d. The keys used in d
are "service_product", "service_version", and "service_extrainfo" (all are
@@ -148,38 +150,45 @@ def get_version_string(d):
result.append("(" + d["service_extrainfo"] + ")")
return " ".join(result)
def get_addrs(host):
if host is None:
return None
return host.get_addrs_for_sort()
def cmp_addrs(host_a, host_b):
return cmp(get_addrs(host_a), get_addrs(host_b))
def cmp_port_list_addr(model, iter_a, iter_b):
host_a = model.get_value(iter_a, 0)
host_b = model.get_value(iter_b, 0)
return cmp_addrs(host_a, host_b)
def cmp_port_tree_addr(model, iter_a, iter_b):
host_a = model.get_value(iter_a, 0)
host_b = model.get_value(iter_b, 0)
return cmp_addrs(host_a, host_b)
def cmp_host_list_addr(model, iter_a, iter_b):
host_a = model.get_value(iter_a, 2)
host_b = model.get_value(iter_b, 2)
return cmp_addrs(host_a, host_b)
def cmp_host_tree_addr(model, iter_a, iter_b):
host_a = model.get_value(iter_a, 2)
host_b = model.get_value(iter_b, 2)
return cmp_addrs(host_a, host_b)
class ScanOpenPortsPage(gtk.ScrolledWindow):
def __init__(self):
gtk.ScrolledWindow.__init__(self)
self.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.__create_widgets()
@@ -188,6 +197,7 @@ class ScanOpenPortsPage(gtk.ScrolledWindow):
def __create_widgets(self):
self.host = HostOpenPorts()
class HostOpenPorts(HIGVBox):
def __init__(self):
HIGVBox.__init__(self)
@@ -203,8 +213,10 @@ class HostOpenPorts(HIGVBox):
# host hostname icon port protocol state service version
# The hostname column is shown only when more than one host is selected
# (hence port_tree not port_list is used).
self.port_list = gtk.ListStore(object, str, str, int, str, str, str, str)
self.port_tree = gtk.TreeStore(object, str, str, int, str, str, str, str)
self.port_list = gtk.ListStore(
object, str, str, int, str, str, str, str)
self.port_tree = gtk.TreeStore(
object, str, str, int, str, str, str, str)
self.port_list.set_sort_func(1000, cmp_port_list_addr)
self.port_list.set_sort_column_id(1000, gtk.SORT_ASCENDING)
@@ -229,8 +241,10 @@ class HostOpenPorts(HIGVBox):
# service icon host hostname port protocol state version
# service is shown only when more than one service is selected (hence
# host_tree not host_list is used).
self.host_list = gtk.ListStore(str, str, object, str, int, str, str, str)
self.host_tree = gtk.TreeStore(str, str, object, str, int, str, str, str)
self.host_list = gtk.ListStore(
str, str, object, str, int, str, str, str)
self.host_tree = gtk.TreeStore(
str, str, object, str, int, str, str, str)
self.host_list.set_sort_func(1000, cmp_host_list_addr)
self.host_list.set_sort_column_id(1000, gtk.SORT_ASCENDING)
@@ -285,7 +299,8 @@ class HostOpenPorts(HIGVBox):
self.host_columns['state'].pack_start(self.cell_port, True)
self.host_columns['service'].set_attributes(self.cell_port, text=0)
self.host_columns['icon'].set_attributes(self.cell_host_icon, stock_id=1)
self.host_columns['icon'].set_attributes(
self.cell_host_icon, stock_id=1)
self.host_columns['hostname'].set_attributes(self.cell_port, text=3)
self.host_columns['port_number'].set_attributes(self.cell_port, text=4)
self.host_columns['protocol'].set_attributes(self.cell_port, text=5)
@@ -294,7 +309,8 @@ class HostOpenPorts(HIGVBox):
self.host_columns['service'].set_visible(False)
self.scroll_ports_hosts.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.scroll_ports_hosts.set_policy(
gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
def _set_port_list(self):
self.port_view.set_enable_search(True)
@@ -315,7 +331,6 @@ class HostOpenPorts(HIGVBox):
self.port_columns[k].set_reorderable(True)
self.port_columns[k].set_resizable(True)
self.port_columns['icon'].set_min_width(35)
self.port_columns['hostname'].set_sort_column_id(1000)
@@ -368,10 +383,14 @@ class HostOpenPorts(HIGVBox):
def freeze(self):
"""Freeze notifications and sorting to make adding lots of elements to
the model faster."""
self.frozen_host_list_sort_column_id = self.host_list.get_sort_column_id()
self.frozen_host_tree_sort_column_id = self.host_tree.get_sort_column_id()
self.frozen_port_list_sort_column_id = self.port_list.get_sort_column_id()
self.frozen_port_tree_sort_column_id = self.port_tree.get_sort_column_id()
self.frozen_host_list_sort_column_id = \
self.host_list.get_sort_column_id()
self.frozen_host_tree_sort_column_id = \
self.host_tree.get_sort_column_id()
self.frozen_port_list_sort_column_id = \
self.port_list.get_sort_column_id()
self.frozen_port_tree_sort_column_id = \
self.port_tree.get_sort_column_id()
self.host_list.set_default_sort_func(lambda *args: -1)
self.host_tree.set_default_sort_func(lambda *args: -1)
self.port_list.set_default_sort_func(lambda *args: -1)
@@ -387,13 +406,17 @@ class HostOpenPorts(HIGVBox):
"""Restore notifications and sorting (after making changes to the
model)."""
if self.frozen_host_list_sort_column_id != (None, None):
self.host_list.set_sort_column_id(*self.frozen_host_list_sort_column_id)
self.host_list.set_sort_column_id(
*self.frozen_host_list_sort_column_id)
if self.frozen_host_tree_sort_column_id != (None, None):
self.host_tree.set_sort_column_id(*self.frozen_host_tree_sort_column_id)
self.host_tree.set_sort_column_id(
*self.frozen_host_tree_sort_column_id)
if self.frozen_port_list_sort_column_id != (None, None):
self.port_list.set_sort_column_id(*self.frozen_port_list_sort_column_id)
self.port_list.set_sort_column_id(
*self.frozen_port_list_sort_column_id)
if self.frozen_port_tree_sort_column_id != (None, None):
self.port_tree.set_sort_column_id(*self.frozen_port_tree_sort_column_id)
self.port_tree.set_sort_column_id(
*self.frozen_port_tree_sort_column_id)
self.host_view.set_model(self.frozen_host_view_model)
self.port_view.set_model(self.frozen_port_view_model)
self.host_view.thaw_child_notify()
@@ -414,7 +437,8 @@ class HostOpenPorts(HIGVBox):
self.host_list.append(entry)
def add_to_port_tree(self, host):
parent = self.port_tree.append(None, [host, host.get_hostname(), None, 0,'','','',''])
parent = self.port_tree.append(
None, [host, host.get_hostname(), None, 0, '', '', '', ''])
for p in host.get_ports():
self.port_tree.append(parent,
[None, '', findout_service_icon(p), int(p.get('portid', "0")),
@@ -422,12 +446,21 @@ class HostOpenPorts(HIGVBox):
p.get('service_name', _("Unknown")), get_version_string(p)])
def add_to_host_tree(self, service_name, ports):
parent = self.host_tree.append(None, [service_name, '', None, '', 0, '', '', ''])
parent = self.host_tree.append(
None, [service_name, '', None, '', 0, '', '', ''])
for p in ports:
self.host_tree.append(parent,
['', findout_service_icon(p), p["host"], p["host"].get_hostname(),
int(p.get('portid', "0")), p.get('protocol', ""),
p.get('port_state', _("Unknown")), get_version_string(p)])
[
'',
findout_service_icon(p),
p["host"],
p["host"].get_hostname(),
int(p.get('portid', "0")),
p.get('protocol', ""),
p.get('port_state', _("Unknown")),
get_version_string(p)
]
)
def switch_port_to_list_store(self):
if self.port_view.get_model() != self.port_list:

View File

@@ -121,12 +121,14 @@
# ***************************************************************************/
import gtk
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox, hig_box_space_holder
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox,\
hig_box_space_holder
from zenmapGUI.higwidgets.higtables import HIGTable
from zenmapGUI.higwidgets.higlabels import HIGEntryLabel
import zenmapCore.I18N
class ScanRunDetailsPage(HIGVBox):
def __init__(self, scan):
HIGVBox.__init__(self)
@@ -146,7 +148,8 @@ class ScanRunDetailsPage(HIGVBox):
self.debug_label = HIGEntryLabel(_('Debug level:'))
self.info_debug_label = HIGEntryLabel(na)
self.command_expander = gtk.Expander("<b>"+_("Command Info")+"</b>")
self.command_expander = gtk.Expander(
"<b>" + _("Command Info") + "</b>")
self.command_expander.set_use_markup(True)
self.command_table = HIGTable()
@@ -158,17 +161,17 @@ class ScanRunDetailsPage(HIGVBox):
self.command_hbox._pack_noexpand_nofill(hig_box_space_holder())
self.command_hbox._pack_noexpand_nofill(self.command_table)
self.command_table.attach(self.command_label,0,1,0,1)
self.command_table.attach(self.info_command_label,1,2,0,1)
self.command_table.attach(self.command_label, 0, 1, 0, 1)
self.command_table.attach(self.info_command_label, 1, 2, 0, 1)
self.command_table.attach(self.nmap_version_label,0,1,1,2)
self.command_table.attach(self.info_nmap_version_label,1,2,1,2)
self.command_table.attach(self.nmap_version_label, 0, 1, 1, 2)
self.command_table.attach(self.info_nmap_version_label, 1, 2, 1, 2)
self.command_table.attach(self.verbose_label,0,1,2,3)
self.command_table.attach(self.info_verbose_label,1,2,2,3)
self.command_table.attach(self.verbose_label, 0, 1, 2, 3)
self.command_table.attach(self.info_verbose_label, 1, 2, 2, 3)
self.command_table.attach(self.debug_label,0,1,3,4)
self.command_table.attach(self.info_debug_label,1,2,3,4)
self.command_table.attach(self.debug_label, 0, 1, 3, 4)
self.command_table.attach(self.info_debug_label, 1, 2, 3, 4)
self.command_expander.add(self.command_hbox)
self._pack_noexpand_nofill(self.command_expander)
@@ -199,7 +202,8 @@ class ScanRunDetailsPage(HIGVBox):
self.closed_label = HIGEntryLabel(_('Closed ports:'))
self.info_closed_label = HIGEntryLabel(na)
self.general_expander = gtk.Expander("<b>"+_("General Info")+"</b>")
self.general_expander = gtk.Expander(
"<b>" + _("General Info") + "</b>")
self.general_expander.set_use_markup(True)
self.general_table = HIGTable()
@@ -211,29 +215,29 @@ class ScanRunDetailsPage(HIGVBox):
self.general_hbox._pack_noexpand_nofill(hig_box_space_holder())
self.general_hbox._pack_noexpand_nofill(self.general_table)
self.general_table.attach(self.start_label,0,1,0,1)
self.general_table.attach(self.info_start_label,1,2,0,1)
self.general_table.attach(self.start_label, 0, 1, 0, 1)
self.general_table.attach(self.info_start_label, 1, 2, 0, 1)
self.general_table.attach(self.finished_label,0,1,1,2)
self.general_table.attach(self.info_finished_label,1,2,1,2)
self.general_table.attach(self.finished_label, 0, 1, 1, 2)
self.general_table.attach(self.info_finished_label, 1, 2, 1, 2)
self.general_table.attach(self.host_up_label,0,1,2,3)
self.general_table.attach(self.info_hosts_up_label,1,2,2,3)
self.general_table.attach(self.host_up_label, 0, 1, 2, 3)
self.general_table.attach(self.info_hosts_up_label, 1, 2, 2, 3)
self.general_table.attach(self.host_down_label,0,1,3,4)
self.general_table.attach(self.info_hosts_down_label,1,2,3,4)
self.general_table.attach(self.host_down_label, 0, 1, 3, 4)
self.general_table.attach(self.info_hosts_down_label, 1, 2, 3, 4)
self.general_table.attach(self.host_scanned_label,0,1,4,5)
self.general_table.attach(self.info_hosts_scanned_label,1,2,4,5)
self.general_table.attach(self.host_scanned_label, 0, 1, 4, 5)
self.general_table.attach(self.info_hosts_scanned_label, 1, 2, 4, 5)
self.general_table.attach(self.open_label,0,1,5,6)
self.general_table.attach(self.info_open_label,1,2,5,6)
self.general_table.attach(self.open_label, 0, 1, 5, 6)
self.general_table.attach(self.info_open_label, 1, 2, 5, 6)
self.general_table.attach(self.filtered_label,0,1,6,7)
self.general_table.attach(self.info_filtered_label,1,2,6,7)
self.general_table.attach(self.filtered_label, 0, 1, 6, 7)
self.general_table.attach(self.info_filtered_label, 1, 2, 6, 7)
self.general_table.attach(self.closed_label,0,1,7,8)
self.general_table.attach(self.info_closed_label,1,2,7,8)
self.general_table.attach(self.closed_label, 0, 1, 7, 8)
self.general_table.attach(self.info_closed_label, 1, 2, 7, 8)
self.general_expander.add(self.general_hbox)
self._pack_noexpand_nofill(self.general_expander)
@@ -260,7 +264,8 @@ class ScanRunDetailsPage(HIGVBox):
self.info_closed_label.set_text(str(scan.get_closed_ports()))
for scaninfo in scan.get_scaninfo():
exp = gtk.Expander('<b>%s - %s</b>' % (_('Scan Info'), scaninfo['type'].capitalize()))
exp = gtk.Expander('<b>%s - %s</b>' % (
_('Scan Info'), scaninfo['type'].capitalize()))
exp.set_use_markup(True)
display = self.make_scaninfo_display(scaninfo)
@@ -277,17 +282,18 @@ class ScanRunDetailsPage(HIGVBox):
table.set_row_spacings(6)
table.set_col_spacings(6)
table.attach(HIGEntryLabel(_('Scan type:')),0,1,0,1)
table.attach(HIGEntryLabel(scaninfo['type']),1,2,0,1)
table.attach(HIGEntryLabel(_('Scan type:')), 0, 1, 0, 1)
table.attach(HIGEntryLabel(scaninfo['type']), 1, 2, 0, 1)
table.attach(HIGEntryLabel(_('Protocol:')),0,1,1,2)
table.attach(HIGEntryLabel(scaninfo['protocol']),1,2,1,2)
table.attach(HIGEntryLabel(_('Protocol:')), 0, 1, 1, 2)
table.attach(HIGEntryLabel(scaninfo['protocol']), 1, 2, 1, 2)
table.attach(HIGEntryLabel(_('# scanned ports:')),0,1,2,3)
table.attach(HIGEntryLabel(scaninfo['numservices']),1,2,2,3)
table.attach(HIGEntryLabel(_('# scanned ports:')), 0, 1, 2, 3)
table.attach(HIGEntryLabel(scaninfo['numservices']), 1, 2, 2, 3)
table.attach(HIGEntryLabel(_('Services:')),0,1,3,4)
table.attach(self.make_services_display(scaninfo['services']),1,2,3,4)
table.attach(HIGEntryLabel(_('Services:')), 0, 1, 3, 4)
table.attach(
self.make_services_display(scaninfo['services']), 1, 2, 3, 4)
hbox._pack_noexpand_nofill(hig_box_space_holder())
hbox._pack_noexpand_nofill(table)

View File

@@ -128,6 +128,7 @@ from zenmapGUI.higwidgets.higbuttons import HIGButton
from zenmapGUI.higwidgets.higscrollers import HIGScrolledWindow
import zenmapCore.I18N
def status_data_func(widget, cell_renderer, model, iter):
entry = model.get_value(iter, 0)
if entry.running:
@@ -143,14 +144,17 @@ def status_data_func(widget, cell_renderer, model, iter):
status = _("Canceled")
cell_renderer.set_property("text", status)
def command_data_func(widget, cell_renderer, model, iter):
entry = model.get_value(iter, 0)
cell_renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
cell_renderer.set_property("text", entry.get_command_string())
class ScanScanListPage(HIGVBox):
"""This is the "Scans" scan results tab. It the list of running and finished
scans contained in the ScansListStore passed to the constructor."""
"""This is the "Scans" scan results tab. It the list of running and
finished scans contained in the ScansListStore passed to the
constructor."""
def __init__(self, scans_store):
HIGVBox.__init__(self)
@@ -159,7 +163,8 @@ class ScanScanListPage(HIGVBox):
scans_store.connect("row-changed", self._row_changed)
self.scans_list = gtk.TreeView(scans_store)
self.scans_list.get_selection().connect("changed", self._selection_changed)
self.scans_list.get_selection().connect(
"changed", self._selection_changed)
status_col = gtk.TreeViewColumn(_("Status"))
cell = gtk.CellRendererText()
@@ -193,9 +198,9 @@ class ScanScanListPage(HIGVBox):
self.cancel_button = HIGButton(_("Cancel Scan"), gtk.STOCK_CANCEL)
buttonbox.pack_start(self.cancel_button, False)
hbox.pack_start(buttonbox, padding = 4)
hbox.pack_start(buttonbox, padding=4)
self.pack_start(hbox, False, padding = 4)
self.pack_start(hbox, False, padding=4)
self._update()
@@ -206,13 +211,13 @@ class ScanScanListPage(HIGVBox):
self._update()
def _update(self):
# Make the Cancel button sensitive or not depending on whether a running
# scan is selected.
# Make the Cancel button sensitive or not depending on whether a
# running scan is selected.
tree_selection = self.scans_list.get_selection()
if tree_selection is None:
# I can't find anything in the PyGTK documentation that suggests
# this is possible, but we received many crash reports that indicate
# it is.
# this is possible, but we received many crash reports that
# indicate it is.
model, selection = None, []
else:
model, selection = tree_selection.get_selected_rows()

View File

@@ -133,7 +133,8 @@ from zenmapGUI.TargetCombo import TargetCombo
class ScanCommandToolbar(HIGHBox):
"""This class builds the toolbar devoted to Command entry. It allows you to retrieve and edit the current command entered."""
"""This class builds the toolbar devoted to Command entry. It allows you to
retrieve and edit the current command entered."""
def __init__(self):
"""Initialize command toolbar"""
HIGHBox.__init__(self)
@@ -249,6 +250,6 @@ if __name__ == "__main__":
box.pack_start(stool)
box.pack_start(sctool)
w.connect("delete-event", lambda x,y: gtk.main_quit())
w.connect("delete-event", lambda x, y: gtk.main_quit())
w.show_all()
gtk.main()

View File

@@ -122,6 +122,7 @@
import gtk
class ScansListStoreEntry(object):
"""This class is an abstraction for running and completed scans, which are
otherwise represented by very different classes."""
@@ -134,11 +135,11 @@ class ScansListStoreEntry(object):
self.command = None
self.parsed = None
def set_running(self, command = None):
def set_running(self, command=None):
self.state = self.RUNNING
self.command = command
def set_finished(self, parsed = None):
def set_finished(self, parsed=None):
self.state = self.FINISHED
self.parsed = parsed
@@ -161,6 +162,7 @@ class ScansListStoreEntry(object):
failed = property(lambda self: self.state == self.FAILED)
canceled = property(lambda self: self.state == self.CANCELED)
class ScansListStore(gtk.ListStore):
"""This is a specialization of a gtk.ListStore that holds running,
completed, and failed scans."""

View File

@@ -129,7 +129,8 @@ import re
import xml.sax
from zenmapGUI.higwidgets.higwindows import HIGWindow
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox, HIGSpacer, hig_box_space_holder
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox, HIGSpacer,\
hig_box_space_holder
from zenmapGUI.higwidgets.higlabels import HIGSectionLabel, HIGEntryLabel
from zenmapGUI.higwidgets.higscrollers import HIGScrolledWindow
from zenmapGUI.higwidgets.higtextviewers import HIGTextView
@@ -149,11 +150,12 @@ from zenmapCore.Name import APP_NAME
paths_config = PathsConfig()
def text_buffer_insert_nsedoc(buf, nsedoc):
"""Inserts NSEDoc at the end of the buffer, with markup turned into proper
tags."""
if not buf.tag_table.lookup("NSEDOC_CODE_TAG"):
buf.create_tag("NSEDOC_CODE_TAG", font = "Monospace")
buf.create_tag("NSEDOC_CODE_TAG", font="Monospace")
for event in zenmapCore.NSEDocParser.nsedoc_parse(nsedoc):
if event.type == "paragraph_start":
buf.insert(buf.get_end_iter(), "\n")
@@ -164,13 +166,15 @@ def text_buffer_insert_nsedoc(buf, nsedoc):
elif event.type == "list_end":
pass
elif event.type == "list_item_start":
buf.insert(buf.get_end_iter(), u"\u2022\u00a0") # bullet nbsp
buf.insert(buf.get_end_iter(), u"\u2022\u00a0") # bullet nbsp
elif event.type == "list_item_end":
buf.insert(buf.get_end_iter(), "\n")
elif event.type == "text":
buf.insert(buf.get_end_iter(), event.text)
elif event.type == "code":
buf.insert_with_tags_by_name(buf.get_end_iter(), event.text, "NSEDOC_CODE_TAG")
buf.insert_with_tags_by_name(
buf.get_end_iter(), event.text, "NSEDOC_CODE_TAG")
class ScriptHelpXMLContentHandler (xml.sax.handler.ContentHandler):
"""A very simple parser for --script-help XML output. This could extract
@@ -183,11 +187,13 @@ class ScriptHelpXMLContentHandler (xml.sax.handler.ContentHandler):
def startElement(self, name, attrs):
if name == u"directory":
if not attrs.has_key(u"name"):
raise ValueError(u"\"directory\" element did not have \"name\" attribute")
if u"name" not in attrs:
raise ValueError(
u'"directory" element did not have "name" attribute')
dirname = attrs[u"name"]
if not attrs.has_key(u"path"):
raise ValueError(u"\"directory\" element did not have \"path\" attribute")
if u"path" not in attrs:
raise ValueError(
u'"directory" element did not have "path" attribute')
path = attrs[u"path"]
if dirname == u"scripts":
self.scripts_dir = path
@@ -197,8 +203,9 @@ class ScriptHelpXMLContentHandler (xml.sax.handler.ContentHandler):
# Ignore.
pass
elif name == u"script":
if not attrs.has_key(u"filename"):
raise ValueError(u"\"script\" element did not have \"filename\" attribute")
if u"filename" not in attrs:
raise ValueError(
u'"script" element did not have "filename" attribute')
self.script_filenames.append(attrs[u"filename"])
@staticmethod
@@ -209,6 +216,7 @@ class ScriptHelpXMLContentHandler (xml.sax.handler.ContentHandler):
parser.parse(f)
return handler
class ScriptInterface:
# Timeout, in milliseconds, after the user stops typing and we update the
# interface from --script.
@@ -216,9 +224,9 @@ class ScriptInterface:
# Timeout, in milliseconds, between polls of the Nmap subprocess.
NMAP_DELAY = 200
def __init__(self,root_tabs,ops,update_command,help_buf):
self.hmainbox = HIGHBox(False,0)
self.notscripttab = False # to show profile editor that it is a script tab
def __init__(self, root_tabs, ops, update_command, help_buf):
self.hmainbox = HIGHBox(False, 0)
self.notscripttab = False # show profile editor it is a script tab
self.nmap_process = None
self.script_list_timeout_id = None
self.nmap_timeout_id = None
@@ -240,16 +248,16 @@ class ScriptInterface:
# Arg name, arg value, (name, desc) tuple.
self.arg_liststore = gtk.ListStore(str, str, object)
# This is what is shown initially. After the initial Nmap run to get the
# list of script is finished, this will be replaced with a TreeView
# This is what is shown initially. After the initial Nmap run to get
# the list of script is finished, this will be replaced with a TreeView
# showing the scripts or an error message.
self.script_list_container = gtk.VBox()
self.script_list_container.pack_start(self.make_please_wait_widget())
self.hmainbox.pack_start(self.script_list_container, False, False, 0)
self.nmap_error_widget = gtk.Label(_("""\
There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
"""))
self.nmap_error_widget = gtk.Label(_(
"There was an error getting the list of scripts from Nmap. "
"Try upgrading Nmap."))
self.nmap_error_widget.set_line_wrap(True)
self.nmap_error_widget.show_all()
@@ -269,8 +277,8 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
def get_script_list(self, rules, callback):
"""Start an Nmap subprocess in the background with
"--script-help=<rules> -oX -", and set it up to call the given callback when
finished."""
"--script-help=<rules> -oX -", and set it up to call the given callback
when finished."""
ops = NmapOptions()
ops.executable = paths_config.nmap_command_path
@@ -279,11 +287,12 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
command_string = ops.render_string()
# Separate stderr to avoid breaking XML parsing with "Warning: File
# ./nse_main.lua exists, but Nmap is using...".
stderr = tempfile.TemporaryFile(mode = "rb", prefix = APP_NAME + "-script-help-stderr-")
stderr = tempfile.TemporaryFile(
mode="rb", prefix=APP_NAME + "-script-help-stderr-")
log.debug("Script interface: running %s" % repr(command_string))
nmap_process = NmapCommand(command_string)
try:
nmap_process.run_scan(stderr = stderr)
nmap_process.run_scan(stderr=stderr)
except Exception, e:
callback(False, None)
stderr.close()
@@ -292,14 +301,17 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
self.script_list_widget.set_sensitive(False)
gobject.timeout_add(self.NMAP_DELAY, self.script_list_timer_callback, nmap_process, callback)
gobject.timeout_add(
self.NMAP_DELAY, self.script_list_timer_callback,
nmap_process, callback)
def script_list_timer_callback(self, process, callback):
try:
status = process.scan_state()
except:
status = None
log.debug("Script interface: script_list_timer_callback %s" % repr(status))
log.debug("Script interface: script_list_timer_callback %s" % \
repr(status))
if status == True:
# Still running, schedule this timer to check again.
@@ -326,7 +338,8 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
def handle_initial_script_list_output(self, process):
process.stdout_file.seek(0)
try:
handler = ScriptHelpXMLContentHandler.parse_nmap_script_help(process.stdout_file)
handler = ScriptHelpXMLContentHandler.parse_nmap_script_help(
process.stdout_file)
except (ValueError, xml.sax.SAXParseException), e:
log.debug("--script-help parse exception: %s" % str(e))
return False
@@ -342,12 +355,14 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
log.debug("--script-help error: no nselib directory")
return False
log.debug("Script interface: scripts dir %s" % repr(handler.scripts_dir))
log.debug("Script interface: nselib dir %s" % repr(handler.nselib_dir))
log.debug("Script interface: scripts dir %s" % repr(
handler.scripts_dir))
log.debug("Script interface: nselib dir %s" % repr(handler.nselib_dir))
# Make a dict of script metadata entries.
entries = {}
for entry in get_script_entries(handler.scripts_dir, handler.nselib_dir):
for entry in get_script_entries(
handler.scripts_dir, handler.nselib_dir):
entries[entry.filename] = entry
self.liststore.clear()
@@ -367,7 +382,8 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
def update_script_list_from_spec(self, spec):
"""Callback method for user edit delay."""
log.debug("Script interface: update_script_list_from_spec %s" % repr(spec))
log.debug("Script interface: update_script_list_from_spec %s" % repr(
spec))
if spec:
self.get_script_list(spec, self.update_script_list_cb)
else:
@@ -383,7 +399,8 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
def handle_update_script_list_output(self, process):
process.stdout_file.seek(0)
try:
handler = ScriptHelpXMLContentHandler.parse_nmap_script_help(process.stdout_file)
handler = ScriptHelpXMLContentHandler.parse_nmap_script_help(
process.stdout_file)
except (ValueError, xml.sax.SAXParseException), e:
log.debug("--script-help parse exception: %s" % str(e))
return False
@@ -422,29 +439,41 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
character."""
if self.script_list_timeout_id:
gobject.source_remove(self.script_list_timeout_id)
self.script_list_timeout_id = gobject.timeout_add(self.SCRIPT_LIST_DELAY, self.update_script_list_from_spec, spec)
self.script_list_timeout_id = gobject.timeout_add(
self.SCRIPT_LIST_DELAY,
self.update_script_list_from_spec, spec)
def parse_script_args(self,raw_argument):
def parse_script_args(self, raw_argument):
"""When the command line is edited, this function is called to update
the script arguments display according to the value of --script-args."""
the script arguments display according to the value of
--script-args."""
arg_dict = parse_script_args_dict(raw_argument)
if arg_dict is None: # if there is parsing error args_dict holds none
if arg_dict is None: # if there is parsing error args_dict holds none
self.arg_values.clear()
else:
for key in arg_dict.keys():
self.arg_values[key] = arg_dict[key]
def update_argument_values(self,raw_argument):
def update_argument_values(self, raw_argument):
"""When scripting tab starts up, argument values are updated."""
if raw_argument is not None:
self.parse_script_args(raw_argument)
def set_help_texts(self):
"""Sets the help texts to be displayed."""
self.list_scripts_help = _("List of scripts\n\nA list of all installed scripts. Activate or deactivate a script by clicking the box next to the script name.")
self.description_help = _("Description\n\nThis box shows the categories a script belongs to. In addition, it gives a detailed description of the script which is present in script. A URL points to online NSEDoc documentation.")
self.argument_help = _("Arguments\n\nA list of arguments that affect the selected script. Enter a value by clicking in the value field beside the argument name.")
self.list_scripts_help = _("""List of scripts
A list of all installed scripts. Activate or deactivate a script \
by clicking the box next to the script name.""")
self.description_help = _("""Description
This box shows the categories a script belongs to. In addition, it gives a \
detailed description of the script which is present in script. A URL points \
to online NSEDoc documentation.""")
self.argument_help = _("""Arguments
A list of arguments that affect the selected script. Enter a value by \
clicking in the value field beside the argument name.""")
def make_please_wait_widget(self):
vbox = gtk.VBox()
@@ -454,7 +483,8 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
return vbox
def make_script_list_widget(self):
"""Creates and packs widgets associated with left hand side of Interface."""
"""Creates and packs widgets associated with left hand side of
Interface."""
vbox = gtk.VBox()
scrolled_window = HIGScrolledWindow()
@@ -485,7 +515,8 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
vbox.pack_start(scrolled_window, True, True, 0)
self.file_scrolled_window = HIGScrolledWindow()
self.file_scrolled_window.set_policy(gtk.POLICY_ALWAYS, gtk.POLICY_ALWAYS)
self.file_scrolled_window.set_policy(
gtk.POLICY_ALWAYS, gtk.POLICY_ALWAYS)
self.file_scrolled_window.set_size_request(175, -1)
self.file_scrolled_window.hide()
self.file_scrolled_window.set_no_show_all(True)
@@ -511,11 +542,12 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
vbox.pack_start(self.file_scrolled_window, False)
hbox = HIGHBox(False, 2)
self.remove_file_button = HIGButton(stock = gtk.STOCK_REMOVE)
self.remove_file_button.connect("clicked", self.remove_file_button_clicked_cb)
self.remove_file_button = HIGButton(stock=gtk.STOCK_REMOVE)
self.remove_file_button.connect(
"clicked", self.remove_file_button_clicked_cb)
self.remove_file_button.set_sensitive(False)
hbox.pack_end(self.remove_file_button)
add_file_button = HIGButton(stock = gtk.STOCK_ADD)
add_file_button = HIGButton(stock=gtk.STOCK_ADD)
add_file_button.connect("clicked", self.add_file_button_clicked_cb)
hbox.pack_end(add_file_button)
@@ -542,7 +574,7 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
else:
self.file_liststore.append([filename, True])
def strip_file_name(self,filename):
def strip_file_name(self, filename):
"""Removes a ".nse" extension from filename if present."""
if(filename.endswith(".nse")):
return filename[:-4]
@@ -579,8 +611,8 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
text_view = gtk.TextView()
text_view.connect("enter-notify-event", self.update_help_desc_cb)
self.text_buffer = text_view.get_buffer()
self.text_buffer.create_tag("Usage", font = "Monospace")
self.text_buffer.create_tag("Output", font = "Monospace")
self.text_buffer.create_tag("Usage", font="Monospace")
self.text_buffer.create_tag("Output", font="Monospace")
text_view.set_wrap_mode(gtk.WRAP_WORD)
text_view.set_editable(False)
text_view.set_justification(gtk.JUSTIFY_LEFT)
@@ -606,7 +638,7 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
arg_listview.append_column(val_col)
arg_col.pack_start(argument, True)
arg_col.add_attribute(argument, "text", 0)
val_col.pack_start(self.value,True)
val_col.pack_start(self.value, True)
val_col.add_attribute(self.value, "text", 1)
arg_window.add(arg_listview)
@@ -614,7 +646,7 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
return vbox
def value_edited_cb(self,cell,path,new_text,model):
def value_edited_cb(self, cell, path, new_text, model):
"""Called when the argument cell is edited."""
self.arg_list = []
model[path][1] = new_text
@@ -637,21 +669,22 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
self.ops["--script-args"] = ",".join(self.arg_list)
self.update_command()
def selection_changed_cb(self,selection):
def selection_changed_cb(self, selection):
"""Called back when the list of scripts is selected."""
model, selection = selection.get_selected_rows()
for path in selection:
check_value = model.get_value(model.get_iter(path),1)
entry = model.get_value(model.get_iter(path),2)
check_value = model.get_value(model.get_iter(path), 1)
entry = model.get_value(model.get_iter(path), 2)
self.set_description(entry)
self.populate_arg_list(entry)
self.focussedentry = entry #Remember the currently pointing script entry
# Remember the currently pointing script entry
self.focussedentry = entry
def update_help_ls_cb(self,widget,extra): # list of scripts
def update_help_ls_cb(self, widget, extra): # list of scripts
"""Callback method to display the help for the list of scripts."""
self.help_buf.set_text(self.list_scripts_help)
def update_help_desc_cb(self,widget,extra):
def update_help_desc_cb(self, widget, extra):
"""Callback method for displaying description."""
self.help_buf.set_text(self.description_help)
@@ -672,14 +705,17 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
arg_name, arg_desc = model.get_value(model.get_iter(path), 2)
if arg_desc is not None:
self.help_buf.set_text("")
self.help_buf.insert(self.help_buf.get_end_iter(), text = "%s\n" % arg_name)
self.help_buf.insert(
self.help_buf.get_end_iter(), text="%s\n" % arg_name)
text_buffer_insert_nsedoc(self.help_buf, arg_desc)
else:
self.help_buf.set_text("")
def add_file_button_clicked_cb(self, button):
if self.script_file_chooser is None:
self.script_file_chooser = zenmapGUI.FileChoosers.ScriptFileChooserDialog(title = _("Select script files"))
self.script_file_chooser = \
zenmapGUI.FileChoosers.ScriptFileChooserDialog(
title=_("Select script files"))
response = self.script_file_chooser.run()
filenames = self.script_file_chooser.get_filenames()
self.script_file_chooser.hide()
@@ -702,7 +738,7 @@ There was an error getting the list of scripts from Nmap. Try upgrading Nmap.\
self.remove_file_button.set_sensitive(False)
self.set_script_from_selection()
def set_description(self,entry):
def set_description(self, entry):
"""Sets the content that is to be displayed in the description box."""
self.text_buffer.set_text(u"")
@@ -711,20 +747,25 @@ Categories: %(cats)s
""" % {"cats": ", ".join(entry.categories)})
text_buffer_insert_nsedoc(self.text_buffer, entry.description)
if entry.usage:
self.text_buffer.insert(self.text_buffer.get_end_iter(), "\nUsage\n")
self.text_buffer.insert_with_tags_by_name(self.text_buffer.get_end_iter(), entry.usage, "Usage")
self.text_buffer.insert(
self.text_buffer.get_end_iter(), "\nUsage\n")
self.text_buffer.insert_with_tags_by_name(
self.text_buffer.get_end_iter(), entry.usage, "Usage")
if entry.output:
self.text_buffer.insert(self.text_buffer.get_end_iter(), "\nOutput\n")
self.text_buffer.insert_with_tags_by_name(self.text_buffer.get_end_iter(), entry.output, "Output")
self.text_buffer.insert(
self.text_buffer.get_end_iter(), "\nOutput\n")
self.text_buffer.insert_with_tags_by_name(
self.text_buffer.get_end_iter(), entry.output, "Output")
if entry.url:
self.text_buffer.insert(self.text_buffer.get_end_iter(), "\n" + entry.url)
self.text_buffer.insert(
self.text_buffer.get_end_iter(), "\n" + entry.url)
def populate_arg_list(self,entry):
def populate_arg_list(self, entry):
"""Called when a particular script is hovered over to display its
arguments and values (if any)."""
self.arg_liststore.clear()
self.current_arguments = []
self.value.set_property('editable',True)
self.value.set_property('editable', True)
for arg in entry.arguments:
arg_name, arg_desc = arg
self.current_arguments.append(arg)

View File

@@ -128,8 +128,10 @@ import copy
from zenmapGUI.higwidgets.higwindows import HIGWindow
from zenmapGUI.higwidgets.higboxes import HIGVBox
from zenmapGUI.higwidgets.higbuttons import HIGButton, HIGToggleButton
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox, HIGSpacer, hig_box_space_holder
from zenmapGUI.higwidgets.higlabels import HIGSectionLabel, HIGEntryLabel, HintWindow
from zenmapGUI.higwidgets.higboxes import HIGVBox, HIGHBox, HIGSpacer,\
hig_box_space_holder
from zenmapGUI.higwidgets.higlabels import HIGSectionLabel, HIGEntryLabel,\
HintWindow
from zenmapGUI.higwidgets.higtables import HIGTable
from zenmapGUI.higwidgets.higdialogs import HIGAlertDialog
@@ -161,14 +163,16 @@ class SearchParser(object):
self.search_gui = search_gui
self.search_dict = search_gui.search_dict
# We need to make an operator->searchkey mapping, since the search entry
# field and the search classes have different syntax.
# We need to make an operator->searchkey mapping, since the search
# entry field and the search classes have different syntax.
#
# NOTE: if you want to add a new search key not handled by the SearchResult
# class, you should add a new method match_CRITERIANAME to the SearchResult class.
# For example, if you'd like a "noodles" criteria, you need to create the method
# SearchResult.match_noodles(self, noodles_string). To see how searches are
# actually performed, start reading from the SearchResult.search() method.
# NOTE: if you want to add a new search key not handled by the
# SearchResult class, you should add a new method match_CRITERIANAME to
# the SearchResult class. For example, if you'd like a "noodles"
# criteria, you need to create the method
# SearchResult.match_noodles(self, noodles_string). To see how searches
# are actually performed, start reading from the SearchResult.search()
# method.
self.ops2keys = copy.deepcopy(search_keywords)
# This is not really an operator (see below)
@@ -198,16 +202,18 @@ class SearchParser(object):
else:
self.search_dict["keyword"] = [word]
# Check if we have any dir: operators in our map, and if so, add them to the
# search_gui object and remove them from the map. The dir: operator isn't a real
# operator, in a sense that it doesn't need to be processed by the
# SearchResult.search() function. It is needed only to create a new SearchDir
# object, which is then used to perform the actual search().
# Check if we have any dir: operators in our map, and if so, add them
# to the search_gui object and remove them from the map. The dir:
# operator isn't a real operator, in a sense that it doesn't need to be
# processed by the SearchResult.search() function. It is needed only to
# create a new SearchDir object, which is then used to perform the
# actual search().
if "dir" in self.search_dict:
self.search_gui.init_search_dirs(self.search_dict["dir"])
else:
self.search_gui.init_search_dirs([])
class SearchGUI(gtk.VBox, object):
"""This class is a VBox that holds the search entry field and buttons on
top, and the results list on the bottom. The "Cancel" and "Open" buttons
@@ -230,25 +236,28 @@ class SearchGUI(gtk.VBox, object):
self.id = 0
self.search_window = search_window
# The Search* objects are created once per Search Window invocation, so that
# they get a list of scans only once, not whenever the search conditions change
# The Search* objects are created once per Search Window invocation, so
# that they get a list of scans only once, not whenever the search
# conditions change
if self.options["search_db"]:
try:
self.search_db = SearchDB()
except ImportError, e:
self.search_db = SearchDummy()
self.no_db_warning.show()
self.no_db_warning.set_text("""\
Warning: The database of saved scans is not available. (%s.) Use \
"Include Directory" under "Expressions" to search a directory.\
""" % str(e))
self.no_db_warning.set_text(
'Warning: The database of saved scans is not '
'available. (%s.) Use "Include Directory" under '
'"Expressions" to search a directory.' % str(e))
# Search directories can be added via the "dir:" operator, so it needs to be a map
# Search directories can be added via the "dir:" operator, so it needs
# to be a map
self.search_dirs = {}
self.init_search_dirs()
# We create an empty search dictionary, since SearchParser will fill it
# with keywords as it encounters different operators in the search string.
# with keywords as it encounters different operators in the search
# string.
self.search_dict = dict()
# We need to define our own keyword search dictionary
search_keywords = dict()
@@ -286,42 +295,48 @@ Warning: The database of saved scans is not available. (%s.) Use \
search_keywords["ir"] = "in_route"
self.search_parser = SearchParser(self, search_keywords)
# This list holds the (operator, argument) tuples, parsed from the GUI criteria rows
# This list holds the (operator, argument) tuples, parsed from the GUI
# criteria rows
self.gui_criteria_list = []
# Do an initial "empty" search, so that the results window initially holds
# all scans in the database
# Do an initial "empty" search, so that the results window initially
# holds all scans in the database
self.search_parser.update("")
self.start_search()
def init_search_dirs(self, dirs = []):
def init_search_dirs(self, dirs=[]):
# Start fresh
self.search_dirs.clear()
# If specified, add the search directory from the Zenmap config file to the map
# If specified, add the search directory from the Zenmap config file to
# the map
conf_dir = self.options["directory"]
if conf_dir:
self.search_dirs[conf_dir] = SearchDir(conf_dir, self.options["file_extension"])
self.search_dirs[conf_dir] = SearchDir(
conf_dir, self.options["file_extension"])
# Process any other dirs (as added by the dir: operator)
for dir in dirs:
self.search_dirs[dir] = SearchDir(dir, self.options["file_extension"])
self.search_dirs[dir] = SearchDir(
dir, self.options["file_extension"])
def _create_widgets(self):
# Search box and buttons
self.search_top_hbox = HIGHBox()
self.search_label = HIGSectionLabel(_("Search:"))
self.search_entry = gtk.Entry()
self.expressions_btn = HIGToggleButton(_("Expressions "), gtk.STOCK_EDIT)
self.expressions_btn = HIGToggleButton(
_("Expressions "), gtk.STOCK_EDIT)
# The quick reference tooltip button
self.search_tooltip_btn = HIGButton(" ", gtk.STOCK_INFO)
# The expression VBox. This is only visible once the user clicks on "Expressions"
# The expression VBox. This is only visible once the user clicks on
# "Expressions"
self.expr_vbox = gtk.VBox()
# Results section
self.result_list = gtk.ListStore(str, str, int) # title, date, id
self.result_list = gtk.ListStore(str, str, int) # title, date, id
self.result_view = gtk.TreeView(self.result_list)
self.result_scrolled = gtk.ScrolledWindow()
self.result_title_column = gtk.TreeViewColumn(_("Scan"))
@@ -341,13 +356,14 @@ Warning: The database of saved scans is not available. (%s.) Use \
self.search_top_hbox.pack_start(self.expressions_btn, False)
self.search_top_hbox.pack_start(self.search_tooltip_btn, False)
# The expressions (if any) should be tightly packed so that they don't take
# too much screen real-estate
# The expressions (if any) should be tightly packed so that they don't
# take too much screen real-estate
self.expr_vbox.set_spacing(0)
# Packing the result section
self.result_scrolled.add(self.result_view)
self.result_scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.result_scrolled.set_policy(
gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
# Packing it all together
self.set_spacing(4)
@@ -366,21 +382,24 @@ Warning: The database of saved scans is not available. (%s.) Use \
hint_window.show_all()
def expressions_clicked(self, widget=None, extra=None):
if len(self.expr_vbox.get_children()) == 0 and self.search_entry.get_text() == "":
if (len(self.expr_vbox.get_children()) == 0 and
self.search_entry.get_text() == ""):
# This is the first time the user has clicked on "Show Expressions"
# and the search entry box is empty, so we add a single Criterion row
# and the search entry box is empty, so we add a single Criterion
# row
self.expr_vbox.pack_start(Criterion(self))
if self.expressions_btn.get_active():
# The Expressions GUI is about to be displayed. It needs to reflect all the
# conditions in the search entry field, so a comparison between the entry field
# and the GUI needs to be performed.
# The Expressions GUI is about to be displayed. It needs to reflect
# all the conditions in the search entry field, so a comparison
# between the entry field and the GUI needs to be performed.
# Make the search entry field insensitive while expressions are visible
# Make the search entry field insensitive while expressions are
# visible
self.search_entry.set_sensitive(False)
# Get a map of operator => argument from the Expressions GUI so that
# we can compare them with the ones in the search entry field
# Get a map of operator => argument from the Expressions GUI so
# that we can compare them with the ones in the search entry field
gui_ops = {}
for criterion in self.expr_vbox.get_children():
if criterion.operator in gui_ops:
@@ -389,19 +408,22 @@ Warning: The database of saved scans is not available. (%s.) Use \
gui_ops[criterion.operator] = [criterion.argument]
# We compare the search entry field to the Expressions GUI. Every
# (operator, value) pair must be present in the GUI after this loop is done.
# (operator, value) pair must be present in the GUI after this loop
# is done.
for op, args in self.search_dict.iteritems():
for arg in args:
if (op not in gui_ops) or (arg not in gui_ops[op]):
# We need to add this pair to the GUI
self.expr_vbox.pack_start(Criterion(self, op, arg), False)
self.expr_vbox.pack_start(
Criterion(self, op, arg), False)
# Now we check if there are any leftover criterion rows that aren't present
# in the search_dict (for example, if a user has deleted something from the
# search entry field)
# Now we check if there are any leftover criterion rows that aren't
# present in the search_dict (for example, if a user has deleted
# something from the search entry field)
for criterion in self.expr_vbox.get_children():
if criterion.operator not in self.search_dict or \
criterion.argument not in self.search_dict[criterion.operator]:
if (criterion.operator not in self.search_dict or
criterion.argument not in self.search_dict[
criterion.operator]):
criterion.destroy()
# If we have deleted all rows, add an empty one
if len(self.expr_vbox.get_children()) == 0:
@@ -410,8 +432,9 @@ Warning: The database of saved scans is not available. (%s.) Use \
# Display all elements
self.expr_vbox.show_all()
else:
# The Expressions GUI is about to be hidden. No updates to the search entry field
# are necessary, since it gets updated on every change in one of the criterion rows.
# The Expressions GUI is about to be hidden. No updates to the
# search entry field are necessary, since it gets updated on every
# change in one of the criterion rows.
self.expr_vbox.hide_all()
self.search_entry.set_sensitive(True)
@@ -450,7 +473,8 @@ Warning: The database of saved scans is not available. (%s.) Use \
def add_search_dir(self, dir):
if dir not in self.search_dirs:
self.search_dirs[dir] = SearchDir(dir, self.options["file_extension"])
self.search_dirs[dir] = SearchDir(
dir, self.options["file_extension"])
def update_search_entry(self, widget, extra=None):
"""Called when the search entry field is modified."""
@@ -459,10 +483,14 @@ Warning: The database of saved scans is not available. (%s.) Use \
def start_search(self):
if not self.options["search_db"] and not self.options["directory"]:
d = HIGAlertDialog(message_format=_("No search method selected!"),
secondary_text=_("%s can search results on directories or \
inside it's own database. Please, select a method by choosing a directory or by checking \
the search data base option at the 'Search options' tab before start the search") % APP_DISPLAY_NAME)
d = HIGAlertDialog(
message_format=_("No search method selected!"),
secondary_text=_(
"%s can search results on directories or inside its "
"own database. Please select a method by choosing a "
"directory or by checking the search data base option "
"in the 'Search options' tab before starting a search"
) % APP_DISPLAY_NAME)
d.run()
d.destroy()
return
@@ -488,8 +516,9 @@ the search data base option at the 'Search options' tab before start the search"
# self.append_result(result)
# matched += 1
self.search_window.set_label_text("Matched <b>%s</b> out of <b>%s</b> scans." % \
(str(matched), str(total)))
self.search_window.set_label_text(
"Matched <b>%s</b> out of <b>%s</b> scans." % (
str(matched), str(total)))
def clear_result_list(self):
for i in range(len(self.result_list)):
@@ -505,7 +534,6 @@ the search data base option at the 'Search options' tab before start the search"
except ValueError:
date_field = _("Unknown")
self.parsed_results[self.id] = [title, parsed_result]
self.result_list.append([title, date_field, self.id])
self.id += 1
@@ -554,11 +582,11 @@ the search data base option at the 'Search options' tab before start the search"
class Criterion(gtk.HBox):
"""This class holds one criterion row, represented as an HBox.
It holds a ComboBox and a Subcriterion's subclass instance, depending on the
selected entry in the ComboBox. For example, when the 'Target' option is
selected, a SimpleSubcriterion widget is displayed, but when the 'Date'
operator is selected, a DateSubcriterion widget is displayed."""
"""This class holds one criterion row, represented as an HBox. It holds a
ComboBox and a Subcriterion's subclass instance, depending on the selected
entry in the ComboBox. For example, when the 'Target' option is selected, a
SimpleSubcriterion widget is displayed, but when the 'Date' operator is
selected, a DateSubcriterion widget is displayed."""
def __init__(self, search_window, operator="keyword", argument=""):
"""A reference to the search window is passed so that we can call
@@ -571,17 +599,18 @@ class Criterion(gtk.HBox):
# We need this as a map, so that we can pass the operator into
# the SimpleSubcriterion instance
self.combo_entries = {"Keyword" : ["keyword"],
"Profile Name" : ["profile"],
"Target" : ["target"],
"Options" : ["option"],
"Date" : ["date", "after", "before"],
"Operating System" : ["os"],
"Port" : ["open", "scanned", "closed", "filtered",
"unfiltered", "open_filtered", "closed_filtered"],
"Service" : ["service"],
"Host In Route" : ["inroute"],
"Include Directory" : ["dir"]}
self.combo_entries = {"Keyword": ["keyword"],
"Profile Name": ["profile"],
"Target": ["target"],
"Options": ["option"],
"Date": ["date", "after", "before"],
"Operating System": ["os"],
"Port": ["open", "scanned", "closed", "filtered",
"unfiltered", "open_filtered",
"closed_filtered"],
"Service": ["service"],
"Host In Route": ["inroute"],
"Include Directory": ["dir"]}
self._create_widgets()
self._pack_widgets()
@@ -591,7 +620,8 @@ class Criterion(gtk.HBox):
# A ComboBox containing the list of operators
self.operator_combo = gtk.combo_box_new_text()
# Sort all the keys from combo_entries and make an entry for each of them
# Sort all the keys from combo_entries and make an entry for each of
# them
sorted_entries = self.combo_entries.keys()
sorted_entries.sort()
for name in sorted_entries:
@@ -605,7 +635,8 @@ class Criterion(gtk.HBox):
break
# Create a subcriterion
self.subcriterion = self.new_subcriterion(self.default_operator, self.default_argument)
self.subcriterion = self.new_subcriterion(
self.default_operator, self.default_argument)
# The "add" and "remove" buttons
self.add_btn = HIGButton(" ", gtk.STOCK_ADD)
@@ -674,6 +705,7 @@ class Criterion(gtk.HBox):
operator = property(get_operator)
argument = property(get_argument)
class Subcriterion(gtk.HBox):
"""This class is a base class for all subcriterion types. Depending on the
criterion selected in the Criterion's ComboBox, a subclass of Subcriterion
@@ -685,9 +717,11 @@ class Subcriterion(gtk.HBox):
self.argument = ""
def value_changed(self):
"""Propagates the operator and the argument up to the Criterion parent."""
"""Propagates the operator and the argument up to the Criterion
parent."""
self.get_parent().value_changed(self.operator, self.argument)
class SimpleSubcriterion(Subcriterion):
"""This class represents all 'simple' criterion types that need only an
entry box in order to define the criterion."""
@@ -716,6 +750,7 @@ class SimpleSubcriterion(Subcriterion):
self.argument = widget.get_text()
self.value_changed()
class PortSubcriterion(Subcriterion):
"""This class shows the port criterion GUI."""
def __init__(self, operator="open", argument=""):
@@ -736,11 +771,12 @@ class PortSubcriterion(Subcriterion):
self.label = gtk.Label(" is ")
self.port_state_combo = gtk.combo_box_new_text()
states = ["open", "scanned", "closed", "filtered", "unfiltered", "open|filtered",
"closed|filtered"]
states = ["open", "scanned", "closed", "filtered", "unfiltered",
"open|filtered", "closed|filtered"]
for state in states:
self.port_state_combo.append_text(state)
self.port_state_combo.set_active(states.index(self.operator.replace("_", "|")))
self.port_state_combo.set_active(
states.index(self.operator.replace("_", "|")))
def _pack_widgets(self):
self.pack_start(self.entry, True)
@@ -759,6 +795,7 @@ class PortSubcriterion(Subcriterion):
self.operator = widget.get_active_text()
self.value_changed()
class DirSubcriterion(Subcriterion):
def __init__(self, operator="dir", argument=""):
Subcriterion.__init__(self)
@@ -797,13 +834,14 @@ class DirSubcriterion(Subcriterion):
self.argument = widget.get_text()
self.value_changed()
class DateSubcriterion(Subcriterion):
def __init__(self, operator="date", argument=""):
Subcriterion.__init__(self)
self.text2op = {"is" : "date",
"after" : "after",
"before" : "before"}
self.text2op = {"is": "date",
"after": "after",
"before": "before"}
self.operator = operator
@@ -811,7 +849,8 @@ class DateSubcriterion(Subcriterion):
self._pack_widgets()
self._connect_widgets()
# Count the fuzzy operators, so that we can append them to the argument later
# Count the fuzzy operators, so that we can append them to the argument
# later
self.fuzzies = argument.count("~")
argument = argument.replace("~", "")
self.minus_notation = False
@@ -821,9 +860,11 @@ class DateSubcriterion(Subcriterion):
self.argument = argument
elif re.match("[-|\+]\d+$", argument) != None:
# Convert the date from the "-n" notation into YYYY-MM-DD
parsed_date = datetime.date.fromordinal(datetime.date.today().toordinal() + int(argument))
parsed_date = datetime.date.fromordinal(
datetime.date.today().toordinal() + int(argument))
self.argument = argument
self.date = datetime.date(parsed_date.year, parsed_date.month, parsed_date.day)
self.date = datetime.date(
parsed_date.year, parsed_date.month, parsed_date.day)
self.minus_notation = True
else:
@@ -851,7 +892,8 @@ class DateSubcriterion(Subcriterion):
self.pack_start(self.date_button, True)
def _connect_widgets(self):
self.date_criterion_combo.connect("changed", self.date_criterion_changed)
self.date_criterion_combo.connect(
"changed", self.date_criterion_changed)
self.date_button.connect("clicked", self.show_calendar)
def date_criterion_changed(self, widget=None, extra=None):
@@ -897,6 +939,7 @@ class DateSubcriterion(Subcriterion):
date = property(get_date, set_date)
_date = datetime.date.today()
class DateCalendar(gtk.Window, object):
def __init__(self):
gtk.Window.__init__(self, gtk.WINDOW_POPUP)
@@ -906,7 +949,7 @@ class DateCalendar(gtk.Window, object):
self.add(self.calendar)
def connect_calendar(self, update_button_cb):
self.calendar.connect("day-selected-double-click", \
self.calendar.connect("day-selected-double-click",
self.kill_calendar, update_button_cb)
def kill_calendar(self, widget, method):

View File

@@ -135,6 +135,7 @@ hildon = None
if is_maemo():
import hildon
class BaseSearchWindow(hildon.Window):
def __init__(self):
hildon.Window.__init__(self)
@@ -151,6 +152,7 @@ else:
def _pack_widgets(self):
self.vbox.set_border_width(4)
class SearchWindow(BaseSearchWindow, object):
def __init__(self, load_method, append_method):
BaseSearchWindow.__init__(self)
@@ -200,7 +202,8 @@ class SearchWindow(BaseSearchWindow, object):
def _connect_widgets(self):
# Double click on result, opens it
self.search_gui.result_view.connect("row-activated", self.open_selected)
self.search_gui.result_view.connect(
"row-activated", self.open_selected)
self.btn_open.connect("clicked", self.open_selected)
self.btn_append.connect("clicked", self.append_selected)
@@ -214,14 +217,16 @@ class SearchWindow(BaseSearchWindow, object):
def set_label_text(self, text):
self.bottom_label.set_label(text)
def open_selected(self, widget=None, path=None, view_column=None, extra=None):
def open_selected(self, widget=None, path=None, view_column=None,
extra=None):
# Open selected results
self.load_method(self.results)
# Close Search Window
self.close()
def append_selected(self, widget=None, path=None, view_column=None, extra=None):
def append_selected(self, widget=None, path=None, view_column=None,
extra=None):
# Append selected results
self.append_method(self.results)

View File

@@ -124,6 +124,7 @@ import gtk
from zenmapCore.TargetList import target_list
class TargetCombo(gtk.ComboBoxEntry):
def __init__(self):
gtk.ComboBoxEntry.__init__(self, gtk.ListStore(str), 0)
@@ -143,7 +144,7 @@ class TargetCombo(gtk.ComboBoxEntry):
t_list = target_list.get_target_list()
for target in t_list[:15]:
t_model.append([target.replace('\n','')])
t_model.append([target.replace('\n', '')])
def add_new_target(self, target):
target_list.add_target(target)

View File

@@ -144,6 +144,7 @@ from radialnet.util.integration import make_graph_from_hosts
SLOW_LIMIT = 1000
class TopologyPage(HIGVBox):
def __init__(self, inventory):
HIGVBox.__init__(self)
@@ -200,12 +201,14 @@ class TopologyPage(HIGVBox):
self.display_panel.pack_start(self.radialnet, True, True)
def add_scan(self, scan):
"""Parses a given XML file and adds the parsed result to the network inventory."""
"""Parses a given XML file and adds the parsed result to the network
inventory."""
self.network_inventory.add_scan(scan)
self.update_radialnet()
def update_radialnet(self):
"""Creates a graph from network inventory's host list and displays it."""
"""Creates a graph from network inventory's host list and displays
it."""
hosts_up = self.network_inventory.get_hosts_up()
self.slow_label.set_text(_("""\

View File

@@ -136,23 +136,24 @@ import gobject
gtk_version_major, gtk_version_minor, gtk_version_release = gtk.gtk_version
assert gtk_version_major == 2
def gtk_constant_name(group, value):
"""
Returns the (py)GTK+ name of a constant, given its group name
"""
group_response = { -1 : 'gtk.RESPONSE_NONE',
-2 : 'gtk.RESPONSE_REJECT',
-3 : 'gtk.RESPONSE_ACCEPT',
-4 : 'gtk.RESPONSE_DELETE_EVENT',
-5 : 'gtk.RESPONSE_OK',
-6 : 'gtk.RESPONSE_CANCEL',
-7 : 'gtk.RESPONSE_CLOSE',
-8 : 'gtk.RESPONSE_YES',
-9 : 'gtk.RESPONSE_NO',
-10 : 'gtk.RESPONSE_APPLY',
-11 : 'gtk.RESPONSE_HELP' }
group_response = {-1: 'gtk.RESPONSE_NONE',
-2: 'gtk.RESPONSE_REJECT',
-3: 'gtk.RESPONSE_ACCEPT',
-4: 'gtk.RESPONSE_DELETE_EVENT',
-5: 'gtk.RESPONSE_OK',
-6: 'gtk.RESPONSE_CANCEL',
-7: 'gtk.RESPONSE_CLOSE',
-8: 'gtk.RESPONSE_YES',
-9: 'gtk.RESPONSE_NO',
-10: 'gtk.RESPONSE_APPLY',
-11: 'gtk.RESPONSE_HELP'}
groups = {'response' : group_response}
groups = {'response': group_response}
return groups.get(group, {}).get(value, 'Error: constant value not found')

View File

@@ -130,6 +130,7 @@ __all__ = ['HIGHBox', 'HIGVBox']
import gtk
class HIGBox(gtk.Box):
def _pack_noexpand_nofill(self, widget):
self.pack_start(widget, expand=False, fill=False)
@@ -137,6 +138,7 @@ class HIGBox(gtk.Box):
def _pack_expand_fill(self, widget):
self.pack_start(widget, expand=True, fill=True)
class HIGHBox(gtk.HBox, HIGBox):
def __init__(self, homogeneous=False, spacing=12):
gtk.HBox.__init__(self, homogeneous, spacing)
@@ -145,6 +147,7 @@ class HIGHBox(gtk.HBox, HIGBox):
pack_label = HIGBox._pack_noexpand_nofill
pack_entry = HIGBox._pack_expand_fill
class HIGVBox(gtk.VBox, HIGBox):
def __init__(self, homogeneous=False, spacing=12):
gtk.VBox.__init__(self, homogeneous, spacing)
@@ -152,6 +155,7 @@ class HIGVBox(gtk.VBox, HIGBox):
# Packs a widget as a line, so it doesn't expand vertically
pack_line = HIGBox._pack_noexpand_nofill
class HIGSpacer(HIGHBox):
def __init__(self, widget=None):
HIGHBox.__init__(self)
@@ -166,5 +170,6 @@ class HIGSpacer(HIGHBox):
def get_child(self):
return self.child
def hig_box_space_holder():
return gtk.Label(" ")

View File

@@ -130,6 +130,7 @@ __all__ = ['HIGMixButton', 'HIGButton']
import gtk
class HIGMixButton (gtk.HBox):
def __init__(self, title, stock):
gtk.HBox.__init__(self, False, 4)
@@ -146,8 +147,9 @@ class HIGMixButton (gtk.HBox):
self.pack_start(self.align)
self.pack_start(self.hbox1)
class HIGButton (gtk.Button):
def __init__ (self, title="", stock=None):
def __init__(self, title="", stock=None):
if title and stock:
gtk.Button.__init__(self)
content = HIGMixButton(title, stock)
@@ -159,6 +161,7 @@ class HIGButton (gtk.Button):
else:
gtk.Button.__init__(self)
class HIGToggleButton(gtk.ToggleButton):
def __init__(self, title="", stock=None):
if title and stock:

View File

@@ -132,6 +132,7 @@ import gtk
from gtkutils import gtk_version_minor
class HIGDialog(gtk.Dialog):
"""
HIGFied Dialog
@@ -142,6 +143,7 @@ class HIGDialog(gtk.Dialog):
self.vbox.set_border_width(2)
self.vbox.set_spacing(6)
class HIGAlertDialog(gtk.MessageDialog):
"""
HIGfied Alert Dialog.

View File

@@ -130,6 +130,7 @@ import gtk
HIGTextEntry = gtk.Entry
class HIGPasswordEntry(HIGTextEntry):
"""
An entry that masks its text

View File

@@ -132,6 +132,7 @@ import gtk
from higboxes import HIGHBox, hig_box_space_holder
class HIGExpander(gtk.Expander):
def __init__(self, label):
gtk.Expander.__init__(self)

View File

@@ -130,6 +130,7 @@ __all__ = ['HIGFrame']
import gtk
class HIGFrame(gtk.Frame):
"""
Frame without border with bold label.

View File

@@ -126,10 +126,13 @@ higwidgets/higlabels.py
labels related classes
"""
__all__ = ['HIGSectionLabel', 'HIGHintSectionLabel', 'HIGEntryLabel', 'HIGDialogLabel']
__all__ = [
'HIGSectionLabel', 'HIGHintSectionLabel', 'HIGEntryLabel', 'HIGDialogLabel'
]
import gtk
class HIGSectionLabel(gtk.Label):
"""
Bold label, used to define sections
@@ -142,10 +145,11 @@ class HIGSectionLabel(gtk.Label):
self.set_alignment(0, 0.50)
self.set_line_wrap(True)
class HIGHintSectionLabel(gtk.HBox, object):
"""
Bold label used to define sections, with a little icon that shows up a hint when mouse is
over it.
Bold label used to define sections, with a little icon that shows up a hint
when mouse is over it.
"""
def __init__(self, text=None, hint=None):
gtk.HBox.__init__(self)
@@ -156,13 +160,15 @@ class HIGHintSectionLabel(gtk.HBox, object):
self.pack_start(self.label, False, False)
self.pack_start(self.hint, False, False, 5)
class Hint(gtk.EventBox, object):
def __init__(self, hint):
gtk.EventBox.__init__(self)
self.hint = hint
self.hint_image = gtk.Image()
self.hint_image.set_from_stock(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_SMALL_TOOLBAR)
self.hint_image.set_from_stock(
gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_SMALL_TOOLBAR)
self.add(self.hint_image)
@@ -172,6 +178,7 @@ class Hint(gtk.EventBox, object):
hint_window = HintWindow(self.hint)
hint_window.show_all()
class HintWindow(gtk.Window):
def __init__(self, hint):
gtk.Window.__init__(self, gtk.WINDOW_POPUP)
@@ -208,6 +215,7 @@ class HIGEntryLabel(gtk.Label):
self.set_use_markup(True)
self.set_line_wrap(True)
class HIGDialogLabel(gtk.Label):
"""
Centered, line-wrappable label, usually used on dialogs.

View File

@@ -135,6 +135,7 @@ from higlabels import HIGEntryLabel
from higtables import HIGTable
from higentries import HIGTextEntry, HIGPasswordEntry
class HIGLoginDialog(HIGDialog):
"""
A dialog that asks for basic login information (username / password)

View File

@@ -133,8 +133,11 @@ class HIGNotebook(gtk.Notebook):
gtk.Notebook.__init__(self)
self.popup_enable()
class HIGClosableTabLabel(HIGHBox):
__gsignals__ = { 'close-clicked' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()) }
__gsignals__ = {
'close-clicked': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())
}
def __init__(self, label_text=""):
gobject.GObject.__init__(self)

View File

@@ -132,6 +132,7 @@ import gtk
from higboxes import HIGHBox
class HIGLabeledProgressBar(HIGHBox):
def __init__(self, label=None):
HIGHBox.__init__(self)

View File

@@ -130,6 +130,7 @@ __all__ = ['HIGScrolledWindow']
import gtk
class HIGScrolledWindow(gtk.ScrolledWindow):
def __init__(self):
gtk.ScrolledWindow.__init__(self)

View File

@@ -134,12 +134,14 @@ import gobject
from gtkutils import gobject_register
class HIGSpinnerImages:
def __init__(self):
"""This class holds list of GDK Pixbuffers.
- static_pixbufs is used for multiple static pixbuffers
- self.animated_pixbufs is used for the pixbuffers that make up the animation
- self.animated_pixbufs is used for the pixbuffers that make up the
animation
"""
dprint('HIGSpinnerImages::__init__')
@@ -182,7 +184,7 @@ class HIGSpinnerImages:
dprint('HIGSpinnerImages::set_rest_pixbuf')
if not self.static_pixbufs.has_key(name):
if name not in self.static_pixbufs:
raise StaticPixbufNotFound
# self.rest_pixbuf holds the *real* pixbuf, not it's name
@@ -322,6 +324,7 @@ class HIGSpinnerCache:
self.spinner_images.static_pixbufs[key_name].save(path_name,
image_format)
class HIGSpinner(gtk.EventBox):
"""Simple spinner, such as the one found in webbrowsers and file managers.
@@ -331,8 +334,8 @@ class HIGSpinner(gtk.EventBox):
* height, the height that will be set for the images
"""
__gsignals__ = { 'expose-event' : 'override',
'size-request' : 'override' }
__gsignals__ = {'expose-event': 'override',
'size-request': 'override'}
def __init__(self):
gtk.EventBox.__init__(self)
@@ -384,8 +387,8 @@ class HIGSpinner(gtk.EventBox):
if self.timer_task == 0:
self.current_pixbuf = self.cache.spinner_images.rest_pixbuf
else:
self.current_pixbuf = self.cache.spinner_images.animated_pixbufs\
[self.animated_pixbuf_index]
self.current_pixbuf = self.cache.spinner_images.animated_pixbufs[
self.animated_pixbuf_index]
def start(self):
"""Starts the animation"""
@@ -401,11 +404,11 @@ class HIGSpinner(gtk.EventBox):
self.timer_task = 0
self.queue_draw()
def stop(self):
"""Stops the animation
Do the same stuff as pause, but returns the animation to the beggining."""
Do the same stuff as pause, but returns the animation to the
beginning."""
self.pause()
self.animated_pixbuf_index = 0

View File

@@ -133,6 +133,7 @@ import gtk
#from higlabels import *
#from higentries import *
class HIGTable(gtk.Table):
"""
A HIGFied table
@@ -154,4 +155,4 @@ class HIGTable(gtk.Table):
self.attach(widget, x0, x, y0, y, xoptions=gtk.FILL)
def attach_entry(self, widget, x0, x, y0, y):
self.attach(widget, x0, x, y0, y, xoptions=gtk.FILL|gtk.EXPAND)
self.attach(widget, x0, x, y0, y, xoptions=gtk.FILL | gtk.EXPAND)

View File

@@ -130,6 +130,7 @@ __all__ = ['HIGTextView']
import gtk
class HIGTextView(gtk.TextView):
def __init__(self, text=''):
gtk.TextView.__init__(self)

View File

@@ -128,6 +128,7 @@ higwidgets/higwindows.py
import gtk
class HIGWindow(gtk.Window):
"""HIGFied Window"""
def __init__(self, type=gtk.WINDOW_TOPLEVEL):

View File

@@ -130,6 +130,7 @@ __all__ = ['HIGSpinner']
import gobject
def gobject_register(klass):
if gtk_version_minor < 8:
gobject.type_register(klass)