示例#1
0
class Logger():
    def __init__(self, database):
        """ log box """
        builder = Gtk.Builder()  # glade
        builder.add_from_file(
            os.path.dirname(os.path.abspath(__file__)) +
            "/../assets/ui/logger.glade")

        self.database = database

        # log list
        self.notebook = builder.get_object("log-notebook")
        self.log_box = builder.get_object("log-box")
        self.scrolled = builder.get_object("scrolled")

        self.log_liststore = Gtk.ListStore(int, int, str, str, int, str, str,
                                           int, str, int)
        self.log_tree = Gtk.TreeView(model=self.log_liststore)
        self.id = 0

        self.extensions = Extensions()

        for i, column_title in enumerate(
            ["#", "Status", "Start time", "End time", "Pid", "Target",
             "Task"]):
            if i == 1:

                renderer = Gtk.CellRendererProgress()

                column = Gtk.TreeViewColumn(column_title, renderer, value=1)
                column.set_min_width(100)
                column.add_attribute(renderer, "pulse",
                                     7)  #renderer.text = " "
            else:
                renderer = Gtk.CellRendererText()
                column = Gtk.TreeViewColumn(column_title, renderer, text=i)

            self.log_tree.append_column(column)

        # get logs from the database
        self.refresh(self.database)
        self.log_tree.show()

        # pulse progress bar every second
        GObject.timeout_add(100, self._pulse_progressbars)

        # connect events
        self.log_tree.connect("button_press_event", self.mouse_click)
        self.log_tree.connect("row-activated", self.on_row_activated)
        self.log_tree.connect('size-allocate', self._scroll)

        # multi selection
        selection = self.log_tree.get_selection()
        selection.set_mode(Gtk.SelectionMode.MULTIPLE)

        self.log_box.add(self.log_tree)

    def _scroll(self, widget, event, data=None):
        # auto scroll
        adj = self.scrolled.get_vadjustment()
        adj.set_value(adj.get_upper() - adj.get_page_size())

    def refresh(self, db):
        # refresh the log tree with the new database
        self.log_liststore.clear()

        self.database = db
        logs = self.database.get_logs()
        i = 0

        for log in logs:

            self.log_liststore.append([
                log.id, 0, log.start_time, log.end_time, log.pid, log.target,
                log.title, GObject.G_MAXINT, log.extension, i
            ])
            i += 1

        self.log_tree.show()

        return True

    def delete_log(self, widget, logs_selected):
        """ delete a log from the database """

        # ask for confirmation with a dialog
        dialog = Gtk.MessageDialog(Gtk.Window(), 0, Gtk.MessageType.WARNING,
                                   Gtk.ButtonsType.OK_CANCEL, "Delete log(s)?")
        dialog.format_secondary_text("This operation will be irreversible.")
        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            dialog.close()

            for log_id in logs_selected:

                self.database.remove_log(log_id)

                model = self.log_tree.get_model()

                for row in model:
                    if row[0] == log_id:
                        self.log_liststore.remove(row.iter)

        elif response == Gtk.ResponseType.CANCEL:
            dialog.close()

    def add_log(self, pid, title, target, extension):
        """ add a task log """
        self.id -= 1
        self.log_liststore.append([
            self.id, 0,
            str(datetime.datetime.now()).split(".")[0], " ", pid, target,
            title, 1, extension,
            len(self.log_liststore)
        ])

        return self.id

    def complete_log(self, id_task, output):
        """ set at 100% the progressbar """
        model = self.log_tree.get_model()

        for t in model:

            if t[0] == id_task:
                row = t

        id_r = row[0]
        start_dat = row[2]
        end_dat = str(datetime.datetime.now()).split(".")[0]
        pid = row[4]
        target = row[5]
        title = row[6]
        extension = row[8]
        path = row[9]

        iter = model.get_iter(Gtk.TreePath.new_from_string(str(path)))

        progress_bar = 0

        id = self.database.add_log(pid, start_dat, end_dat, title, target,
                                   output, extension)
        self.log_liststore.set_value(iter, 0, id)
        self.log_liststore.set_value(iter, 7, GObject.G_MAXINT)
        self.log_liststore.set_value(iter, 3, end_dat)

    def _pulse_progressbars(self):
        # progress bars task running animation

        model = self.log_tree.get_model()

        for a in range(0, len(model)):
            if len(self.log_liststore[model.get_iter(
                    Gtk.TreePath.new_from_string(str(a)))][3]) < 3:

                self.log_liststore[model.get_iter(
                    Gtk.TreePath.new_from_string(str(a)))][-3] += 1

        return True

    def on_row_activated(self, listbox, cell, listboxrow):

        (model, pathlist) = self.log_tree.get_selection().get_selected_rows()
        for path in pathlist:

            tree_iter = model.get_iter(path)
            log_id = model.get_value(tree_iter, 0)

            self.open_log(log_id)

    def open_log(self, log_id):

        try:

            log = self.database.get_logs(str(log_id))

            extension = self.extensions.get_extra_by_name(log.extension)

            scrolledwindow = extension.get_log(log.output)

            # generate and fill the toolbox
            builder = Gtk.Builder()
            builder.add_from_file(
                os.path.dirname(os.path.abspath(__file__)) +
                "/../assets/ui/logger.glade")

            toolbox = builder.get_object("showlog-box")
            lbl_start_time = builder.get_object("start-time-label")
            lbl_end_time = builder.get_object("end-time-label")
            lbl_pid = builder.get_object("pid-label")
            lbl_name = builder.get_object("extension-name-label")
            lbl_target = builder.get_object("extension-target-label")
            export_button = builder.get_object("export-button")
            delete_button = builder.get_object("delete-button")

            lbl_start_time.set_text(log.start_time)
            lbl_end_time.set_text(log.end_time)
            lbl_pid.set_text(str(log.pid))
            lbl_name.set_text(log.extension)
            lbl_target.set_text(log.target)

            export_button.connect("clicked", self.export_log, log.id)
            delete_button.connect("clicked", self.delete_log, log.id)

            box = Gtk.Box()
            box.pack_start(scrolledwindow, True, True, 0)

            # box label + close button for extension
            box_label = Gtk.Box(spacing=6)
            box_label.add(Gtk.Label("%s %s" % (log.title, log.target)))
            close_image = Gtk.Image.new_from_icon_name("gtk-delete",
                                                       Gtk.IconSize.MENU)
            close_button = Gtk.Button()
            close_button.set_relief(Gtk.ReliefStyle.NONE)
            close_button.add(close_image)
            box_label.add(close_button)

            toolbox.add(box)

            # close task window option
            close_button.connect("clicked", self.close_log_tab, toolbox)

            self.notebook.append_page(toolbox, box_label)
            self.notebook.set_current_page(-1)

            box.show()
            toolbox.show_all()
            box_label.show_all()

            scrolledwindow.show()

        except:
            pass

    def close_log_tab(self, btn, widget):
        """ close a log notebook tab button's event """
        current_tab = self.notebook.page_num(widget)
        self.notebook.remove_page(current_tab)

    def mouse_click(self, tv, event):
        # right click on a log

        try:
            if event.button == 3:

                try:
                    self.rightclickmenu.destroy()
                except:
                    pass

                # get selected port
                self.rightclickmenu = Gtk.Menu()

                logs_selected = []

                (model,
                 pathlist) = self.log_tree.get_selection().get_selected_rows()
                for path in pathlist:

                    tree_iter = model.get_iter(path)

                    end_time = model.get_value(tree_iter, 3)  # selected port
                    pid = model.get_value(tree_iter, 4)  # selected service
                    log_id = model.get_value(tree_iter, 0)

                    logs_selected.append(log_id)

                if len(end_time) < 3:

                    i1 = Gtk.MenuItem("kill")
                    self.rightclickmenu.append(i1)
                    i1.connect("activate", self.kill_task, pid)

                else:
                    i1 = Gtk.MenuItem("export to file")
                    self.rightclickmenu.append(i1)
                    i1.connect("activate", self.export_log, log_id)

                    i2 = Gtk.MenuItem("delete")
                    self.rightclickmenu.append(i2)
                    i2.connect("activate", self.delete_log, logs_selected)

                # show all
                self.rightclickmenu.popup(None, None, None, None, 0,
                                          Gtk.get_current_event_time())
                self.rightclickmenu.show_all()

        except:
            pass

    def kill_task(self, widget, pid):
        # kill a task
        os.killpg(os.getpgid(pid), signal.SIGKILL)

    def export_log(self, widget, log_id):
        # export a log in a txt file
        log = self.database.get_logs(log_id)
        text = log.output

        dialog = Gtk.FileChooserDialog(
            "Please choose a filename", None, Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE,
             Gtk.ResponseType.OK))

        dialog.set_filename("export output")
        file_filters.add_filter_txt(dialog)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            file_selected = dialog.get_filename()

            try:
                file = open(file_selected, "w")

                for line in text:
                    file.write(line)

                file.close()
            except:
                pass

        elif response == Gtk.ResponseType.CANCEL:
            dialog.destroy()

        dialog.destroy()
示例#2
0
class Handler:
    def __init__(self):
        """ badkarma handler class """

        # initialization

        self.tasks = {}  # task queue
        self.outfiles = {}  # scan import queue
        self.scenes      = {  # saved Gtk scenes of hostview
              "hosts_view"    : {},
              "services_view" : {},
             }

        self._selected_opt = {  # user selection dict
            "host": "",
            "port": "",
            "domain": "",
            "service": ""
        }

        self.database = DB()
        self.extensions = Extensions()  # extension engine

        self.on_services_view = False

        # generate main window
        self.main = Main()

        # set db location as window subtitle
        self.main.headerbar.set_subtitle(self.database.db_loc)

        self.main.window.connect("delete-event", self.on_window_delete_event)

        # main menu
        self.main.file_addtarget.connect("clicked", self.add_target)
        self.main.file_quit.connect("clicked", self.on_window_delete_event)
        self.main.file_open.connect("clicked", self.open_file)
        self.main.file_import.connect("clicked", self.import_file)
        self.main.file_save_as.connect("clicked", self.save_file_as)

        self.portlist_empty = True

        # preferences
        self.main.view_logs.connect("toggled", self._showhide_logs)

        # initialization
        # workspace & hostlist
        self.main.controller_notebook.connect('switch-page',
                                              self._controller_switch)

        # generate the logger
        self.logger = Logger(self.database)

        # generate the host list
        self.services_list = Serviceslist(self.database)
        self.host_list = Hostlist(self.database)

        # generate the services list
        self.main.services_box.add(self.services_list.services_box)
        self.main.hostlist_box.add(self.host_list.host_box)

        # connect host list events
        self.host_list.hosttree.connect("row-activated", self.on_row_activated)
        self.host_list.hosttree.connect("button_press_event", self.host_click)

        # cennect services slist events
        self.services_list.servicestree.connect("row-activated",
                                                self.services_row)
        self.services_list.servicestree.connect(
            "button_press_event", self.host_click)  #self.service_click)

        # add welcome messages
        self.main.workspace.add(self.main.welcome_note)
        #self.main.workspace.add(self.services_view.welcome_note)

        # add logger
        self.main.main_paned.add2(self.logger.notebook)

        # populate window
        self._sync()

        # show all
        self.main.window.show_all()

    def _sync(self, reset=False, history=False):
        """ Sync UI and DB """

        # Check history refresh
        if history:
            # this sync only the hosts history in the hostviews loaded
            # this avoid to refresh everything and lose the hostlist/servicelist selection
            # then return True

            for host in self.scenes["hosts_view"]:
                self.scenes["hosts_view"][host].refresh(self.database,
                                                        history=True)

            return True

        # refresh everithing
        self.host_list.refresh(self.database)
        self.services_list.refresh(self.database)

        if reset:
            # called at project switch
            # otherwise will break current running task's log
            self.logger.refresh(self.database)

        # set the db location as headerbar subtitle
        self.main.headerbar.set_subtitle(self.database.db_loc)

        # refresh the hostviews and servicesview
        for host in self.scenes["hosts_view"]:
            self.scenes["hosts_view"][host].refresh(self.database)

        for service in self.scenes["services_view"]:
            self.scenes["services_view"][service].refresh(self.database)

    def _clear_workspace(self):
        """ 
		remove host_view or services_view notebook
		    and welcome notebook 
		"""

        try:
            self.main.workspace.remove(self.main.welcome_note)
        except:
            pass
        try:
            self.main.workspace.remove(self.services_view.welcome_note)
        except:
            pass
        try:
            self.main.workspace.remove(self.services_view.notebook)
        except:
            pass
        try:
            self.main.workspace.remove(self.work.notebook)
        except:
            pass

        return True

    def _filter_service(self, service):
        """ function to replace service name """
        service = service.replace("soap", "http").replace(
            "https", "http").replace("ssl", "http").replace(
                "http-proxy", "http").replace("http-alt", "http").replace(
                    "ajp13",
                    "http").replace("vnc-http",
                                    "http").replace("http-mgmt", "http")
        service = service.replace("microsoft-ds", "netbios-ssn")
        service = service.replace("imaps",
                                  "imap").replace("pop3s", "pop3").replace(
                                      "smtps",
                                      "smtp").replace("pop3pw", "pop3")
        service = service.replace("psql", "postgresql")

        return service

    def _controller_switch(self, widget, test, newpage):
        """ switch from hostview to services view and vice-versa """
        if newpage == 0:
            # switch to host view
            self.on_services_view = False

            try:
                self.main.workspace.remove(self.services_view.notebook)

            except:
                self.main.workspace.remove(self.main.welcome_note)

            try:
                self.main.workspace.add(self.work.notebook)

            except:
                # empty workspace
                self.main.workspace.add(self.main.welcome_note)

        elif newpage == 1:
            # switch to servies view

            self.on_services_view = True

            try:

                self.main.workspace.remove(self.work.notebook)
            except:
                self.main.workspace.remove(self.main.welcome_note)
            try:

                self.main.workspace.add(self.services_view.notebook)

            except:
                # empty workspace
                self.main.workspace.add(self.main.welcome_note)

        # clear the mouse_click menu
        try:
            self.rightclickmenu.destroy()
        except:
            pass

    def _showhide_logs(self, widget):
        """ show / hide logs notebook """

        if self.main.view_logs.get_active():
            self.logger.notebook.show()

        else:
            self.logger.notebook.hide()

    def _sensitive_true(self, widget, add):
        # close the add target dialog

        if add:
            target = self.add_window.target_input.get_text()

            self._selected_opt["host"] = target
            self._selected_opt["service"] = "hostlist"
            self._selected_opt["port"] = 0

            if self.add_window.hostdiscovery.get_active():
                # user chose to scan the new host
                # we will add it using the run_ext function
                # using all the accrocco
                active = self.add_window.nmap_combo.get_active()
                model = self.add_window.nmap_combo.get_model()

                button_workaround = Gtk.Button()
                button_workaround.set_label(model[active][0])

                self.run_extra(button_workaround,
                               self.extensions.get_extra_by_name("shell"),
                               "hostlist")
                self.add_window.window.destroy()
                self.main.window.set_sensitive(True)

            else:
                # user chose to not scan the host
                # only add it's address to the database
                # and sync the ui
                if self.add_window.add_host():
                    self.main.window.set_sensitive(True)
                    self._sync()
                    self.add_window.window.destroy()

        else:
            self.add_window.window.destroy()
            self.main.window.set_sensitive(True)

    def add_target(self, widget):
        """ add one or multiple targets """
        self.main.window.set_sensitive(False)
        self.add_window = Targetadd(self.database)
        self.add_window.cancel_button.connect("clicked", self._sensitive_true,
                                              False)
        self.add_window.add_button.connect("clicked", self._sensitive_true,
                                           True)
        self.add_window.window.connect("close", self._sensitive_true, False)

    def open_file(self, widget):
        """ open a sqlite project file"""

        dialog = Gtk.FileChooserDialog(
            "Please choose a file", None, Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))

        file_filters.add_filter_database(dialog)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            file_selected = dialog.get_filename()
            try:
                self.database = DB(db_loc=file_selected)

            except Exception as e:
                print(e)

        elif response == Gtk.ResponseType.CANCEL:
            dialog.destroy()

        dialog.destroy()

        # update the hostlist
        self._clear_workspace()
        self._sync(reset=True)

    def save_file_as(self, widget):
        """ save the project's sqlite database """

        dialog = Gtk.FileChooserDialog(
            "Please choose a filename", None, Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE,
             Gtk.ResponseType.OK))

        dialog.set_filename("project")
        file_filters.add_filter_database(dialog)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            file_selected = dialog.get_filename()
            try:
                shutil.copy(self.database.db_loc, file_selected)
            except:
                pass

        elif response == Gtk.ResponseType.CANCEL:
            dialog.destroy()

        dialog.destroy()

    def import_file(self, widget):
        """ import nmap xml """

        dialog = Gtk.FileChooserDialog(
            "Please choose a file", None, Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))

        file_filters.add_filter_nmap(dialog)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            file_selected = dialog.get_filename()
            try:
                self.database.import_nmap(file_selected)
            except Exception as e:
                print(e)

        elif response == Gtk.ResponseType.CANCEL:
            dialog.destroy()

        dialog.destroy()
        self._sync()

    def _delete_host(self, widget):
        """ Delete host from database """

        # ask for confirmation with a dialog
        dialog = Gtk.MessageDialog(self.main.window, 0,
                                   Gtk.MessageType.WARNING,
                                   Gtk.ButtonsType.OK_CANCEL,
                                   "Delete host(s)?")
        dialog.format_secondary_text("This operation will be irreversible.")
        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            dialog.close()

            (model, pathlist
             ) = self.host_list.hosttree.get_selection().get_selected_rows()
            for path in pathlist:

                tree_iter = model.get_iter(path)
                oldid = model.get_value(tree_iter, 4)
                #print(path)
                self.host_list.host_liststore.remove(tree_iter)

                self.database.remove_host(oldid)

            #self._sync()

        elif response == Gtk.ResponseType.CANCEL:
            dialog.close()

    def services_row(self, listbox, cell, listboxrow):
        """ serviceslist service click event
		    this will generate the scene in the scenes dictionary """

        self._clear_workspace()

        if str(cell) in self.scenes["services_view"]:

            # check if the scene was already loaded
            self.services_view = self.scenes["services_view"][str(cell)]

        else:

            # get selected port
            (model, pathlist) = self.services_list.servicestree.get_selection(
            ).get_selected_rows()
            for path in pathlist:

                tree_iter = model.get_iter(path)
                #selected_host = model.get_value(tree_iter,1)
                selected_service = model.get_value(tree_iter,
                                                   0)  # selected service

                # YO
                self._selected_opt["service"] = selected_service

            # generate the scene
            self.services_view = Serviceview(selected_service, self.database)
            self.scenes["services_view"][str(cell)] = self.services_view

        # add the scene
        self._selected_opt["service"] = self.services_view.service
        self.main.workspace.add(self.services_view.notebook)

        self.services_view.treeview.connect("button_press_event",
                                            self.mouse_click)

    def on_row_activated(self, listbox, cell, listboxrow):
        """ Generate the treeView for the ports """

        self._clear_workspace()

        (model, pathlist
         ) = self.host_list.hosttree.get_selection().get_selected_rows()
        for path in pathlist:

            tree_iter = model.get_iter(path)
            host_id = model.get_value(tree_iter, 4)  # selected host address

            if str(host_id) in self.scenes["hosts_view"]:
                # check if the scene was already loaded
                self.work = self.scenes["hosts_view"][str(host_id)]

            else:
                # generate the scene
                db_host = self.database.get_host(host_id)
                self.work = Hostview(db_host, self.database)
                self.scenes["hosts_view"][str(host_id)] = self.work

        # add the scene
        self._selected_opt["host"] = self.work.host.address
        self._selected_opt["domain"] = self.work.host.hostname
        self.main.workspace.add(self.work.notebook)

        self.work.treeview.connect("button_press_event", self.mouse_click)

    def run_multi_extra(self, widget, targets, ext, service):
        """ take a screenshot on multiple targets """
        for serv in targets:
            try:
                # target is a port
                self._selected_opt["host"] = serv.host.address
                self._selected_opt["port"] = serv.port
            except:
                # target is a host
                self._selected_opt["host"] = serv.address

            self.run_extra(widget, ext, service)

    def host_click(self, tv, event):
        """ right click on a host event """

        # grab the right click
        if event.button == 3:

            try:
                self.rightclickmenu.destroy()
            except:
                pass

            self.rightclickmenu = Gtk.Menu()

            # get selected host
            try:
                targets = []
                if self.on_services_view:
                    (model,
                     pathlist) = self.services_list.servicestree.get_selection(
                     ).get_selected_rows()
                else:
                    (model, pathlist) = self.host_list.hosttree.get_selection(
                    ).get_selected_rows()

                if len(pathlist) < 1:
                    # right click on nothing
                    return False

                for path in pathlist:
                    tree_iter = model.get_iter(path)

                    if self.on_services_view:

                        service = self._filter_service(
                            model.get_value(tree_iter, 0))  # selected service

                        for port in self.database.get_ports_by_service(
                                service):
                            targets.append(port)

                    else:
                        #print("provone")
                        address = model.get_value(tree_iter,
                                                  1)  # selected host address
                        domain = model.get_value(tree_iter,
                                                 2)  # selected host address
                        host_id = model.get_value(tree_iter, 4)

                        targets.append(self.database.get_host(host_id))

                        self._selected_opt["host"] = address
                        self._selected_opt["domain"] = domain
                        self._selected_opt["port"] = 0

                if self.on_services_view:
                    extra_name = service

                else:
                    i4 = Gtk.MenuItem("Delete")
                    i4.show()

                    self.rightclickmenu.append(i4)
                    i4.connect("activate", self._delete_host)

                    extra_name = "hostlist"

                extra = self.extensions.get_extra(extra_name)

                for c_ext in extra:
                    tabs = {}

                    try:
                        for extension in extra[c_ext].submenu(extra_name):

                            # remove _ and show spaces
                            extension = extension.replace("_", " ")

                            if len(extension.split(" ")) > 1:
                                if not extension.split(" ")[0] in tabs:

                                    i3 = Gtk.MenuItem(extension.split(" ")[0])
                                    i3.show()

                                    tabs[extension.split(" ")[0]] = []
                                    tabs[extension.split(" ")[0]].append(
                                        Gtk.Menu())
                                    tabs[extension.split(" ")[0]].append(i3)

                                    self.rightclickmenu.append(i3)

                                item = Gtk.MenuItem(extension)
                                tabs[extension.split(" ")[0]][0].append(item)

                            else:

                                item = Gtk.MenuItem(extension)
                                item.show()
                                self.rightclickmenu.append(item)

                            item.connect("activate", self.run_multi_extra,
                                         targets, extra[c_ext], extra_name)

                        # show all
                        for menu in tabs:
                            tabs[menu][0].hide()
                            tabs[menu][1].set_submenu(tabs[menu][0])

                    except:
                        if self.on_services_view:
                            item = Gtk.MenuItem(c_ext)
                            item.show()
                            self.rightclickmenu.append(item)

                            item.connect("activate", self.run_multi_extra,
                                         targets, extra[c_ext], service)

                self.rightclickmenu.popup(None, None, None, None, 0,
                                          Gtk.get_current_event_time())
                self.rightclickmenu.show_all()

                return True

            except Exception as e:
                print(e)

    def mouse_click(self, tv, event):
        """ right click on a service event """

        if event.button == 3:

            try:
                self.rightclick_service_menu.destroy()
                self.rightclickmenu.destroy()
            except:
                pass

            # create the menu and submenu objects
            self.rightclick_service_menu = Gtk.Menu()
            self.rightclickmenu = Gtk.Menu()

            targets = []
            generic = []

            # check
            if self.on_services_view:
                #try:
                (model, pathlist) = self.services_view.treeview.get_selection(
                ).get_selected_rows()

            else:
                (model, pathlist
                 ) = self.work.treeview.get_selection().get_selected_rows()

            if len(pathlist) < 1:
                # right click on nothing
                return False

            # get selected port
            try:
                for path in pathlist:
                    tree_iter = model.get_iter(path)

                    # set selected port
                    selected_port = model.get_value(tree_iter, 1)
                    self._selected_opt["port"] = selected_port

                    if self.on_services_view:
                        # set selected host if on service view
                        self._selected_opt["host"] = model.get_value(
                            tree_iter, 4)
                        targets.append(
                            self.database.get_port(
                                model.get_value(tree_iter, 7)))

                    else:
                        # set selected service if not on service view
                        selected_service = model.get_value(
                            tree_iter, 4)  # selected service
                        targets.append(
                            self.database.get_port(
                                model.get_value(tree_iter, 7)))
                        self._selected_opt["service"] = selected_service

            except:
                pass

            # fix some multiple names
            self._selected_opt["service"] = self._filter_service(
                self._selected_opt["service"])

            # get extra extensions
            extra = self.extensions.get_extra(self._selected_opt["service"])

            for extension in extra:
                if extension == "shell":
                    # little trick for shell ext
                    iE = Gtk.MenuItem(self._selected_opt["service"])
                else:
                    iE = Gtk.MenuItem(extension)

                iE.show()
                self.rightclickmenu.append(iE)

                # check if there is a submenu for the current extension
                try:
                    tabs = {}
                    extension_ext_menu = Gtk.Menu()
                    submenu = extra[extension].submenu(
                        self._selected_opt["service"])

                    for sub_item in submenu:
                        if len(sub_item.split("_")) > 1:
                            if not sub_item.split("_")[0] in tabs:
                                t = Gtk.MenuItem(sub_item.split("_")[0])
                                t.show()
                                tabs[sub_item.split("_")[0]] = []
                                tabs[sub_item.split("_")[0]].append(Gtk.Menu())
                                tabs[sub_item.split("_")[0]].append(t)

                    # remove _ and show spaces
                    for tab in tabs:
                        thetab = Gtk.MenuItem(tabs[tab][1].get_label())
                        extension_ext_menu.append(thetab)
                        thetab.show()
                        thetab.set_submenu(tabs[tab][0])

                    for sub_item in submenu:
                        sub_item = sub_item.replace("_", " ")

                        if len(sub_item.split(" ")) > 1:
                            #print(sub_item)
                            item = Gtk.MenuItem(sub_item)

                            tabs[sub_item.split(" ")[0]][0].append(item)

                        else:
                            # extension in any sub-categories
                            item = Gtk.MenuItem(sub_item)
                            extension_ext_menu.append(item)

                        # show and connect the extension
                        item.show()
                        item.connect('activate', self.run_multi_extra, targets,
                                     extra[extension],
                                     self._selected_opt["service"])

                    iE.set_submenu(extension_ext_menu)

                except:
                    iE.connect('activate', self.run_multi_extra, targets,
                               extra[extension], self._selected_opt["service"])

                try:
                    # try if there is generic for the current extension
                    submenu = extra[extension].submenu("generic")

                    for sub_item in submenu:
                        # remove _ and show spaces
                        generic.append(sub_item.replace("_", " "))
                except:
                    pass

            gen_x = self.extensions.get_extra("generic")

            for gen in generic:

                i2 = Gtk.MenuItem(gen)
                i2.show()
                self.rightclickmenu.append(i2)

                i2.connect("activate", self.run_multi_extra, targets,
                           gen_x["shell"], "generic")

            self.rightclickmenu.popup(None, None, None, None, 0,
                                      Gtk.get_current_event_time())

            return True

    def end_task(self, caller, out, id):
        """ function called when an extension's finish a task """

        self.logger.complete_log(id,
                                 out)  # complete the logger row of the task
        del self.tasks[id]  # delete the task from the running task's dict

        try:
            # check if there is an output file to import
            outfile = self.outfiles[id]

            if os.path.exists(outfile):
                # import the nmap xml and refresh the ui
                self.database.import_nmap(outfile)

                self._sync()
            else:
                self._sync(history=True)

        except:
            pass

    def run_extra(
            self, widget, ext,
            service):  # def run_extra_thread(self, widget, ext, service):
        """ run a python extension """

        # get target strings
        port_string = str(self._selected_opt["port"])
        host_string = self._selected_opt["host"]

        # set the output_file location string
        output_file = ''.join(
            random.choice(string.ascii_uppercase + string.digits)
            for _ in range(8))
        output_file = "/tmp/badkarma-" + output_file + ".xml"

        # config for the extension
        ext_conf = {
            "autoexec":
            self.main.auto_exec.get_active(),
            "proxychains":
            self.main.use_proxychains.get_active(),
            "rhost":
            host_string,
            "rport":
            port_string,
            "menu-sel":
            widget.get_label(),
            "service":
            service,
            "domain":
            self._selected_opt["domain"],
            "outfile":
            output_file,
            "path_config":
            os.path.dirname(os.path.abspath(__file__)) + "/../conf/",
            "path_script":
            os.path.dirname(os.path.abspath(__file__)) + "/../scripts/",
            "path_wordlist":
            os.path.dirname(os.path.abspath(__file__)) + "/../wordlists/"
        }

        ext = self.extensions.get_new(
            ext.name)  # new instance fix for termination signal
        out, pid = ext.task(ext_conf)  # get output and task pid

        # define title for logger and notebook's tabs
        if ext.name == "shell":
            task_name = widget.get_label()
        else:
            task_name = ext.name

        task_title = task_name + " " + host_string

        if ext.log:

            if port_string != "0":
                task_title += ":" + port_string

            id = self.logger.add_log(pid, task_title, ext.name)
            ext.connect('end_task', self.end_task, id)
            self.outfiles[id] = output_file

        try:
            views = ext.read(out)
            views.show()
            try:
                self.tasks[id] = {"views": views, "ext": ext}
            except:
                pass

            # box label + close button for extension
            box_label = Gtk.Box(spacing=6)
            box_label.add(Gtk.Label(task_title))
            close_image = Gtk.Image.new_from_icon_name("gtk-delete",
                                                       Gtk.IconSize.MENU)
            close_button = Gtk.Button()
            close_button.set_relief(Gtk.ReliefStyle.NONE)
            close_button.add(close_image)
            box_label.add(close_button)

            # close task window option
            close_button.connect("clicked", self.close_task_tab, views)

            if self.on_services_view:
                self.services_view.notebook.append_page(views, box_label)
                self.services_view.notebook.set_current_page(-1)
            else:
                self.work.notebook.append_page(views, box_label)
                self.work.notebook.set_current_page(-1)

            box_label.show_all()

        except:
            pass

        return True

    def close_task_tab(self, btn, widget):
        """ event triggered at close button's click """

        if self.on_services_view:
            current_tab = self.services_view.notebook.page_num(widget)
            self.services_view.notebook.remove_page(current_tab)
        else:
            current_tab = self.work.notebook.page_num(widget)
            self.work.notebook.remove_page(current_tab)

    def on_window_delete_event(self, *args):
        # quit

        Gtk.main_quit(*args)
        sys.exit()